Take a look at the new features of Java -- other new features

Posted by blackhorse on Sun, 24 Nov 2019 13:14:40 +0100

A summary of the remaining Java 8 new feature knowledge points, including: default method, Optional, completable future, time related.

Default method

The default methods are all to help new Java functions to be compatible with the programs developed in the lower version of JDK For example, to add new methods to an existing interface of a lower version, whether the classes that originally implemented the interface need to implement new methods is very unfriendly, and is not conducive to upgrading the JDK version of the project, so a new rule default method is introduced.

It is also very simple to use, just add the keyword default before the interface method, and then implement it.

public interface Parent {
    default void hello(){
        System.out.println("hello");
    }
}
public class Son implements Parent {
    public static void main(String[] args) {
        Son son = new Son();
        son.hello();
    }
}

The default method solves the problem of diamond inheritance very well. Although Java is a single inheritance, this problem will not occur in general, but don't forget that Java has not only inheritance, but also implementation. Let's suppose there is such a situation.

Son implements Parent, Parent1. Both Parent and Parent1 inherit GrandParent. There is an abstract method hello in GrandParent, and then son will report an error. If you change the method in GrandParent to the default method, this will be solved for you.

//In this way, Son will report an error
public interface GrandParent {
     void hello();
}
//That's ok
public interface GrandParent {
    default void hello(){
        System.out.println("hello");
    }
}

In fact, with the default method, a Java class can implement N multiple interfaces, no matter how complicated they are. But for the code level, it's better to use the proxy mode, implement a proxy class in advance to encapsulate all interfaces, and inherit the real inherited classes to inherit the proxy classes, which will be very comfortable to use.

Optional

Anyone who has written Java must know the existence of null, which is the direction of those undefined objects. In order to avoid NullPointerException, a lot of if judgments should be added to the code. In order to make this redundant and meaningless code disappear, and to be more consistent with Java design philosophy, Optional came into being.

Optional is to further encapsulate the object created by the user, so that the user object is only a part of the optional object, so for the developer level, the undefined object will not be directly operated.

Create Optional

Suppose our user class is Son in the previous section. Create an Optional that contains the Son object, and the Son object currently points to null. Use the static method Optional.empty().

Optional<Son> optCar = Optional.empty(); 

Then put the existing user object Son into Optional.

Son son = new Son();
Optional<Son> sonOptional = Optional.of(son);

However, to use Optional.of, you need to ensure that the parameter must not be null, otherwise a NullPointerException exception will be thrown. To solve this problem, you can use the following method.

Optional<Son> sonOptional = Optional.ofNullable(son); 

Optional combined flow operation

It's not just the problem of void detection. Optional can be naturally combined with Stream. For convenience, we add the attribute name and age to the Son class.

@Data
public class Son implements Parent,Parent2 {
    private String name;
    private Integer age;
}

Now suppose we need to know the name of the son. First, we need to judge whether the son is empty, and then use the method son.getName(). With Optional, however, we can use map to do this.

//Primitive writing
Son son = null;
if(Objects.nonNull()){
    String name = son.getName();
}
//neographism
Son son = null;
Optional<Son> sonOptional = Optional.of(son);
Optional<String> name = sonOptional.map(Son::getName);

It is worth mentioning whether the object converted by Stream operation is Optional, but the generic type becomes the expected value type.

Optional nesting problem

If you read the Stream blog I wrote last, you must remember that in addition to map, flatMap can merge streams, and the same flatMap can merge multiple nested Optional. For example, in order to illustrate the problem, two new classes of Computer and CPU are created. Obviously, CPU is a part of Computer. We need to know the manufacturer of a brand of Computer CPU.

@Data
public class CPU {
    private String name;
    private String manufacturers;
}
@Data
public class Computer {
    private String name;
    private Optional<CPU> cpu;
}

First, use map to see the effect.

Optional<Computer> optionalComputer = Optional.of(computer);
Optional<String> stringOptional = optionalComputer
    .map(Computer::getCpu)
    .map(CPU::getManufacturers);//Let alone run, this line fails to compile
System.out.println(stringOptional.get());

Line 4 failed to compile. That's because it went through line 3. At this time, the object structure is optional < optional < CPU >, and the generic type is optional < CPU >, unable to call CPU::getManufacturers directly.

So we need to use flatMap to merge the two layers of Optional.

Optional<Computer> optionalComputer = Optional.of(computer);
Optional<String> stringOptional = optionalComputer
    .flatMap(Computer::getCpu)
    .map(CPU::getManufacturers);

ok, perfect execution. Of course, there are many methods in Stream that are applicable here, such as filter.

Optional data reading

The most direct method is get(), but the get() method needs to be empty in advance. If the user object (that is, the object of the generic class) is null, the get() method will report an error.

stringOptional.get()

Of course, you should insist on using the get() method. Java also provides a more friendly method orElse(), which can give a default value when the object is empty.

stringOptional.orElse("juejin")

For orElse(), there is also an upgraded method orElseGet(), which is a delayed version of orElse(). When the default value is used, the parameters of orElseGet() will be calculated, so as to avoid the impact of time-consuming operation on performance.

stringOptional.orElseGet(()->"juejin")

If you want to throw an exception when the object does not exist, you can use the method orElseThrow().

stringOptional.orElseThrow(Exception::new)

There is also a very useful method ifPresent(), which can determine whether an object exists.

if (stringOptional.isPresent()){
    System.out.println("stringOptional.isPresent()");
}

CompletableFuture

Wrote an article Powerful completable future.

New date API

Although there are many formed third-party toolkits, such as Hutool. There are many options for dealing with time issues, but the JDK's own approach not only provides some sense of best practice, but also makes code intrusive almost zero.

LocalDate and LocalTime

I believe that many small partners who have used Java8 have used LocalDateTime. Yes, it is the combination of LocalDate and LocalTime, which control the month, day, hour, minute and second respectively.

LocalDate localDate = LocalDate.of(2019,11,24);
localDate.getYear();
localDate.getMonth();
localDate.getDayOfYear();
LocalTime localTime = LocalTime.of(18,40,03);
localTime.getHour();
localTime.getMinute();
localTime.getSecond();

These two methods are relatively simple, and can read and operate the date, time, minute and second flexibly. However, the real use is their combined version of LocalDateTime.

Instant

This class can get the machine time, which is calculated from 1970. For example, get the time stamp.

Instant instant = Instant.now();
System.out.println(instant.getEpochSecond());

Of course, getEpochSecond() method can also pass parameters, with a certain time interval relative to the current time displacement.

Duration or Period

Duration gets the interval between two times.

Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
Duration d2 = Duration.between(instant1, instant2);

The parameters can be LocalTimes, LocalDateTimes, Instant. The above can calculate the size between seconds and nanoseconds.

If you need to calculate the time interval between year, month and day, you need Period.

Period tenDays = Period.between(LocalDate.of(2014, 3, 8),
                                 LocalDate.of(2014, 3, 18)); 

Time operation

Take the local date times for example. This is the most used time type. The new time type can quickly modify the time.

LocalDateTime localDateTime = LocalDateTime.now();
//Modify the time directly, do not operate on the original data, and generate new objects.
localDateTime.withHour(1).withMonth(1);
//By changing the time of displacement, the new object is generated without the operation of the original data.
localDateTime.plusDays(12);
localDateTime.plusMinutes(33);

TemporalAdjuster

In addition to the displayed modification time, you can also use some pre-defined methods provided by JDK.

import static java.time.temporal.TemporalAdjusters.*;//Note that you need to import like this
LocalDate date1 = LocalDate.of(2019, 11, 24);
System.out.println(date1);//2019-11-24
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
System.out.println(date2);//2019-11-24
LocalDate date3 = date2.with(lastDayOfMonth());
System.out.println(date3);//2019-11-30

See the following table for more operations

DateTimeFormatter

Needless to say, when converting an event type to a String type, you need the style format.

LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:SS",                                     Locale.CHINA);
System.out.println(localDateTime.format(dateTimeFormatter));
//2019-11-24 19:41:77

ZoneId

Handling different time zones, the ZoneId class replaces the original TimeZone class.

LocalDateTime localDateTime = LocalDateTime.now();
ZoneId romeZone = ZoneId.of("Europe/Rome");
ZoneId shangHaiZone = ZoneId.of("Asia/Shanghai");
System.out.println(localDateTime.atZone(romeZone));
System.out.println(localDateTime.atZone(shangHaiZone));
//2019-11-24T19:52:13.105+01:00[Europe/Rome]
//2019-11-24T19:52:13.105+08:00[Asia/Shanghai]

The only annoyance is that the ZoneId.of() parameter is a string (continent / city). There is no enumeration class. It needs to be entered manually by the developer.

My public address

My public number is used for blog synchronization.

Topics: Java JDK Attribute