New features of Java 8

Posted by Large on Sat, 22 Jun 2019 23:15:13 +0200

Java 9 is coming, so we have to sort out Java 8.

Official documents: http://docs.oracle.com/javase/specs/jls/se8/html/index.html

I. Default and static methods of interfaces

The method body can also be written in the interface. The class that implements the interface no longer enforces the implementation of the method, but only needs to add default signature to the method signature and implement the method body, such as:

Interface:

public interface Compute {
    default Integer add(Integer x,Integer y) {
        return x+y;
    }
    Integer minus(Integer x,Integer y);
}

Realization:

public class ComputeImpl implements Compute {

    @Override
    public Integer minus(Integer x, Integer y) {
        return x-y;
    }

    public static void main(String[] args) {
        ComputeImpl c=new ComputeImpl();
        System.out.println(c.add(2, 1));
        System.out.println(c.minus(22, 1));
    }
}

Interfaces can define static methods and call them through interfaces. The implementation class does not need to be implemented, nor can it be invoked directly in the implementation class.

public interface Compute {
    default Integer add(Integer x,Integer y) {
        return x+y;
    }
    Integer minus(Integer x,Integer y);

    static void test() {
        System.out.println("static method test()");
    }
}

When invoked:

Compute.test();

Note: The introduction of default or static methods gives java the capability of C++ -like multiple inheritance, so there are also ambiguities caused by inheritance.

II. Internal Class Accessing External Variables

java7 and before, accessing external variables in internal classes required that external variables be defined as final. The final keyword in Java 8 is not required, but you need to make sure that you do not modify the variable, otherwise you will still compile errors.

External static members and fields can be accessed at will.

The lambda is the same as the internal class.

3. Lambda expression

3.1) What is lambda

http://www.importnew.com/8118.html

Format

lambda is a grammatical sugar, which can improve the coding efficiency when writing code. The actual result after compiling is the same. Such as:

(Class1 p1,Class2 p2...pn) -> {
  statement1;
  statement2;
  //...
  statementn;
}

It corresponds to jdk7 and previous internal classes:

new Interface1(){
  @Override
  public Class1 abstractMethod(Class1 p1,Class2 p2...pn){
    statement1;
    statement2;
    //...
    statementn;
  }
}

(2) lambda format description:

(Class1 p1,Class2 p2...pn) is lambda header, or parameter list, which is the parameter list of the method in the interface.

-> For the lambda operator.

{statementn...;} is a lambda body, which is the code block implemented by the method in the interface.

(3) lambda Code Simplification Rules

Because jdk has code checking during compilation, Java 8 enhances the speculative ability of code checking for lambda. Java 8 can deduce variable types and code block keywords according to context, so it provides the ability of lambda simplification.

  • Variable types in the parameter list can be omitted, and jdk matches according to the parameters in the interface.

  • If there is only one parameter, parentheses in the parameter list can be omitted.

  • If the statement in the body of the method has only one line, braces and semicolons can be omitted. Note that if the body of the method has a return value, the return keyword is also omitted.

(4) The difference between lambda and internal classes

In addition to simplifying the code, if this is referenced in lambda, then this pointer is the wrapper class, that is, the class lambda is invoked; in the inner class, it refers to the inner class.

3.2) Functional Interface

To use the interface in lambda form, it is necessary to use the interface as a special type of interface, that is, functional interface. The so-called function interface is an interface with only one abstract method.

The so-called abstract methods in functional interfaces are not abstract methods in abstract classes. They do not need Abstract Key modifications. They refer to jdk7 and previous methods without method bodies.

Except for the only unrealized method in functional interfaces, there are other default methods with function bodies.

As long as it meets the previous conditions, it is a legitimate functional interface. A comment @Functional Interface is provided in Java 8, annotated on the interface definition, which can be checked at the compilation stage. If the second abstract method is defined in the interface, the compilation will fail. This comment is not required.

@FunctionalInterface
public interface Compute {
    default Integer add(Integer x,Integer y) {
        return x+y;
    }
    Integer minus(Integer x,Integer y);
}

3.3) Testing lambda

(1) No parameter, no return value

Interface definitions:

public interface ICompute {
    public void print();
}

Define the method of using this interface:

private void hello(ICompute c){
  c.print();
}

Test Case 1 - Traditional Internal Class Approach

@Test
    public void testAnonymousInnerClass(){
        int i=12;
        hello(new ICompute() {

            @Override
            public void print() {
                System.out.println(i);//jdk7 will report errors, requiring i to be final; java8 will not report errors, assuming that you will not modify, if you modify, it will report errors.
                System.out.println("Hello anonymous inner class.");
            }
        });
    }

Test Case 2 - lambda

hello(()-> System.out.println("Hello lambda"));

(2) Return value with or without reference

Interface definitions:

public interface FunctionalInterfaceVoidArg {
    public void sayHi(String str);
}

Define the method of using this interface:

private void sayHi(String str,FunctionalInterfaceVoidArg object) {
  object.sayHi(str);
}

Test cases:

@Test
public void testLambdaVoidHasArg(){
  sayHi("peter",x-> System.out.println("Hello "+x));
}

(2) Return value

Interface definitions:

public interface FunctionalInterfaceReturn {
    public String generateTime();
}

Define the method of using this interface:

private String getTime(FunctionalInterfaceReturn fi){
  return fi.generateTime();
}

Test cases:

@Test
public void testLambdaReturn(){
  String str=getTime(()->{
    return String.valueOf(System.currentTimeMillis());
  });
  System.out.println(str);

  //Simplified lambda with brackets and signs omitted
  str=getTime(()->new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
  System.out.println(str);
}

3.4) Specific functional interfaces built into Java 8

① Predicate

Receive a parameter and return a boolen value for conditional judgment.

//Using lambda
Predicate<String> pre=(x)-> x.startsWith("t_");
boolean isTable=pre.startsWith("t_users");
//Use Method Reference
Predicate<Boolean> notNull=Objects::nonNull;
Predicate<Boolean> isNull=Objects::isNull;

Predicate<Sting> isEmpty=String::isEmpty;
Predicate<String> notEmpty=isEmpty.negate();

② Comparator

This is an already existing interface that implements some default methods in Java 8.

3.5) General Functional Interface Built-in in Java 8

① Supplier

package java.util.function;
@FunctionalInterface
public interface Supplier<T>{
  T get();
}

It is suitable for scenarios where there is no entry and return value. Such as producers.

The typical application is List. forEach (Supplier < T > s).

Arrays.asList("aa","bb","cc").forEach((x)->System.out.println(x));

② Consumer

package java.util.function;

@FunctionalInterface
public interface Consumer<T> {
  void accept(T t);
}

It is suitable for scenarios with one input and no return value. For example, consumers.

③ Function

package java.util.function;
@FunctionalInterface
public interface Function<T, R> {
  R apply(T t);
}

Applicable to a type of entry, return a type of scenario.

④ UnaryOperator

package java.util.function;
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
  static <T> UnaryOperator<T> identity() {
    return t -> t;
  }
}

In fact, he is a special case of Function< T, R> that is, Function< T, T>.

⑤ Predicate

package java.util.function;
@FunctionalInterface
public interface Predicate<T>{
  boolean test(T t);
}

It is similar to Function< T, Boolean>, but does not inherit Function for conditional judgment, similar to Predicate in guava.

Other types

Java 8 provides many types in the package java.util.function. If not, you can view javadocs, find the right type, or customize it.

IV. Method Reference

Among the methods that require function parameters, we can pass in another method of the same type directly, which is called method reference binding. Similar to function pointer in C language.

Lambda expressions can replace method references; or method references are a special case of lambda, and method references cannot control the parameters passed.

4.1) Constructor Reference

private Person construntorRef(Supplier<Person> sup){
    Person p=sup.get();
    return p;
}

@Test
public void testConstructorRef(){
    Person p=construntorRef(Person::new);
    System.out.println(p);
}

A parametric or non-parametric constructor is required.

4.2) Static Method Reference

    private static void print(String s){
        System.out.println(s);
    }

    @Test
    public void testStaticRef(){
        Arrays.asList("aa","bb","cc").forEach(TestMethodReference::print);
    }

so easy, as long as the parameter list of the static method is consistent with the parameters required by FI.

4.3) Membership method reference

@Test
    public void testMemberMethodRef(){
        Arrays.asList("aa","bb","cc").forEach(System.out::println);
    }

so easy, as long as the parameter list of member methods is consistent with the parameters required by FI.

4.4) Instance method references to arbitrary objects of a class (weird)

@Test
public void testClassMemberMethodRef(){
    String[] strs={"zzaa","xxbb","yycc"};
    Arrays.sort(strs,String::compareToIgnoreCase);//OK
    System.out.println(Arrays.asList(strs));
    File[] files = new File("C:").listFiles(File::isHidden); // OK
}

(iv) High-powered ahead, please turn off the music of headphones, think carefully and act carefully.

In traditional java development, it is not allowed to use class names to call member methods, which is a basic principle, so the writing here is somewhat difficult to understand. Or illustrate with examples:

Internal classes used:

import lombok.Data;

@Data
public static class Person{
    private String name;
    private Integer age;

    public int mycompare(Person p1){
        return p1.getAge()-this.getAge();
    }
    public void print(){
        System.out.println(this);
    }

    public void println(Person p){
        System.out.println(p);
    }

    public int compareByAge(Person a,Person b){
        return a.getAge().compareTo(b.getAge());
    }
}

public static class APerson{
    public void print(){
        System.out.println(this);
    }

    public void println(Person p){
        System.out.println(p);
    }
}

Test code:

@Test
    public void testClassMemberMethodRef2() {
        // R apply (T); // Require a parameter
        Function<String, String> upperfier1 = String::toUpperCase;
        UnaryOperator<String> upperfier2 = (x) -> x.toUpperCase();//There's no parameter here, zero.

        /*
         * Summary: If the method reference expression "String:: to UpperCase" can be rewritten with the specified member method of the parameter in the lambda expression (the parameter of the member method is one less parameter than the parameter required by FI).
         *  Then you can use "instance methods of classes" to represent method references.
         *  
         *  In other words, if the method used in the lambda body of a lambda expression is the method of parameter matching, then the method reference expression uses "the instance method of the class reference object".
         *  
         *  lambda The parameters are the main body of the method.
         */

        class Print {
            public void println(String s) {
                System.out.println(s);
            }
        }
        // void accept(T t);

        Consumer<String> sysout1 = new Print()::println;
        Consumer<String> sysout2 = (x) -> new Print().println(x);

        /*
         * Summary: If the method refers to the expression "new Print()::println", it can be rewritten by a member method that matches the parameters of the specific object in the lambda expression.
         *  Then use "object instance method" to represent method reference.
         *  
         *  Or, if the method used in the lambda body of a lambda expression operates on the parameters of lambda, then the method reference expression uses the "object instance method".
         *  
         *  lambda The parameters are the parameters of the method.
         */

        //A more confusing example can be verified by the above rule, Arrays. sort (T, Comparator <? Extends > c)

        class Person {
            public int com1(Person p) {
                return 1;
            }

            public int com2(Person p1, Person p2) {
                return 1;
            }
        }

        // int compare(T o1, T o2); // Two parameters are required

        Person[] ps = { new Person(), new Person() };
        Arrays.sort(ps, Person::com1);
        Arrays.sort(ps, (x,y)->x.com1(y));

        Arrays.sort(ps, new Person()::com2);
        Arrays.sort(ps, (x,y)->new Person().com2(x, y));

        //Verification according to the above rules should be clear.

        /*
         * But why are there two ways to write an interface? The default lambda matches the FI method, which is "int compare(T o1, T o2);"
         * From the above lambda expression, the default use of lambda should be:
         */

        Comparator<Person> comparator1 = new Person()::com2;

        /*
         * What about the following way?
         */
        Comparator<Person> comparator2 = Person::com1;
        System.out.println(comparator2);

        /*
        *   Any FI interface method with two parameters (int compare(T o1, T o2)) can be replaced by the method of reducing one parameter by reference (int O1 < T >. compare (To2). If the object itself is used as another implicit parameter, then the object referenced by the method uses the class name to represent any object of the class.

        Or is it a little messy? Let's look at it from a different angle:
        First, we need int compare(T o1, T o2) as two parameters.
        Next, let's not consider: Is the prefix a class or an object, you gave me a compare(T o2), with one less parameter? What should I do?
        lambda To solve this problem, the mechanism uses: the class name of the previous new object, as the missing parameter needed, this is the instance method of the class.
        */
    }

To sum up:

Firstly, the list of method parameters needed here is made clear. The number of marked parameters here is N. Then:

1. If the incoming method is a type of static method, and the parameters match, use the "static method reference of the class"; this should not be difficult to understand.

2. If the incoming method is a member method of an instance, and the parameters match, use the "member method of an instance"; this should not be difficult to understand.

3. If the incoming method is a member method of an instance of type T, and the parameter is N-1, and a parameter of type T is missing, then the "T-type instance method" is used.

Which parameter is omitted in the case method of brain burning analysis class

In the previous example, the two parameters of FI are of the same type. What if the types are different? Which parameter is omitted?

Did you omit the first one by location, or the last one?

Or do they automatically correspond to each other by type, without caring about the number?

At this time, the way we can think of may be to look at the source code, but generally look at the code for a week or even longer, Mao can not see. Let's use an example to analyze it.

Define a FI interface:

package com.pollyduan.fi;

public interface TestInterface {
    //lambda doesn't care about any name, because FI has only one interface and matches by parameters.
    public void anyStringAsName(TestBean1 bean1,TestBean2 bean2);
}

Write two classes for parameters:

TestBean1.java

package com.pollyduan.fi;

public class TestBean1 {
    public void expect1(TestBean1 bean1){

    }
    public void expect2(TestBean2 bean2){

    }
    public void test1(TestInterface i){

    }
}

TestBean2.java

package com.pollyduan.fi;

public class TestBean2 {
    public void expect1(TestBean1 bean1){

    }
    public void expect2(TestBean2 bean2){

    }
    public void test1(TestInterface i){

    }
}

There is little difference between the two.

Write test classes:

package com.pollyduan.fi;

public class TestFIMain {
    public static void main(String[] args) {
        TestBean1 bean1=new TestBean1();
        bean1.test1(TestBean1::expect1);//①
        bean1.test1(TestBean1::expect2);//② ok
        bean1.test1(TestBean2::expect1);//③
        bean1.test1(TestBean2::expect2);//④

        TestBean2 bean2=new TestBean2();
        bean2.test1(TestBean1::expect1);//⑤
        bean2.test1(TestBean1::expect2);//⑥ ok
        bean2.test1(TestBean2::expect1);//⑦
        bean2.test1(TestBean2::expect2);//⑧
    }
}

In the test method, all errors are reported except for the correct line marking OK.

Analysis:

First, we need to make sure that the list of parameters required by FI is: (TestBean1,TestBean2)

  1. Let's first look at line 1. The leading class is TestBean1, and the expect1 method matches the input bean1 of the TestBean1 type, that is to say, omitting the parameter bean2 of the TestBean2 type and the last parameter in FI. Even if we use the class TestBean1 to go to a new object, we can't find TestBean2, so this error.

  2. Let's first look at line 2. The leading class is TestBean1, and the expect2 method matches the input bean2 of the TestBean2 type. That is to say, the parameter bean1 of the TestBean1 type is omitted. Then lambda can use the leading TestBean1 to construct an object as the first parameter to match the FI interface method. ok.

  3. Let's first look at line 3. The leading class is TestBean2, and the expect1 method matches the input bean1 of TestBean1 type, that is to say, the last parameter of bean2 and FI of TestBean2 type is omitted. According to the analysis of the second step, we use the leading class TestBean2 to go to a new object, which should be able to make up two parameters. The actual test will find that this does not work. This proves that only the first parameter can be omitted, and the class leading by ":" must also be the type of the first parameter.

  4. Similar to the first step, the fourth line of code can not find the parameters of TestBean1, and there are errors to understand.

  5. As for_~_, it just replaces the outer test1 body, without any difference. This proves that lambda matching has nothing to do with what kind of ghost the outer layer is, it only cares about the parameter list of FI needed by the outer layer.

  6. Please don't look at the next step, stop here and think calmly. If we change the parameter position of FI method in TestInterface, that is, public void anyString AsName (TestBean2 cat, TestBean1 dog), which two lines should be correct? If you think about it carefully, you really can't understand how to run the test case. It may be more helpful to understand.

  7. If you want to understand that you can use this idea to verify that only the first parameter, TestBean2, can be omitted by referring to the parameter list (TestBean2,TestBean1), then ":" The leading class must be TestBean2, which is used to create objects automatically; and the unomitted parameter is TestBean1, then the method is called expect1, and the result is XX (TestBean2:: ct1), that is, 3 and_, are you right?

V. Enhancement of Container Function

5.1) Collection

List<String> list = Arrays.asList(new String[] { "xxx", "aaa", "zzz", "eee", "yyy", "ccc" });

stream() and parallelStream()

Open the stream
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.stream().parallel();

Stream classes have several factory methods to create Stream:

Stream<Object> stream3 = Stream.builder().add(list).build();

Stream<Object> stream4 = Stream.empty();

Stream<String> stream5 = Stream.of("111");

Stream<String> stream6 = Stream.of("111","222","333");

ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(20);
queue.addAll(list);
Stream<String> stream7 = Stream.generate(()->{
try {
    return queue.take();
} catch (InterruptedException e) {
    e.printStackTrace();
}
return null;
});
stream7.forEach(System.out::println);

Stream<String> stream8 = Stream.concat(list.stream(), list.stream());

In fact, we rarely manipulate Stream objects directly, but as an intermediate result, we end up closing the flow to return data.

Closing flow

Look at the Stream implementation, where methods that return non-Stream objects are methods that return data for closing streams.

Object[] toArray();

<A> A[] toArray(IntFunction<A[]> generator);

T reduce(T identity, BinaryOperator<T> accumulator);

Optional<T> reduce(BinaryOperator<T> accumulator);

<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);

<R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);

<R, A> R collect(Collector<? super T, A, R> collector);

Optional<T> min(Comparator<? super T> comparator);

Optional<T> max(Comparator<? super T> comparator);

long count();

boolean anyMatch(Predicate<? super T> predicate);

boolean allMatch(Predicate<? super T> predicate);

boolean noneMatch(Predicate<? super T> predicate);

Optional<T> findFirst();

Optional<T> findAny();

After the Stream object is opened and closed, it is the main way for us to process the data.

collect()

Convert the stream to a List.

@Test
public void testStreamToList() {
    List<String> list1 = list.stream().collect(Collectors.toList());
}
sort
@Test
public void testStreamSort() {
    System.out.println(list);
    // list.sort((x, y) -> x.compareTo(y));
    List<String> list2 = list.stream().parallel()
            .sorted(Comparator.comparing(String::toLowerCase))
            .collect(Collectors.toList());
    System.out.println(list2);
}
filter
@Test
public void testStreamFilter() {
    System.out.println(list);
    List<String> list2 = list.stream()
            .filter(x->!x.equals("zzz"))
            .collect(Collectors.toList());
    System.out.println(list2);
}
map

Convert case to case

List<String> list...;
list.stream().map(String::toUpperCase).forEach(System.out::println);

Extract local information:

Field[] fields = entityClass.getDeclaredFields();
String fieldNames = Arrays.asList(fields).stream().map(x -> x.getName()).collect(Collectors.joining(","));

Extract local information to Map

Map<String, Integer> peoples = persons.stream().collect(Collectors.toMap(Person::getName, Person::getAge));

forEach()

list.forEach(x->System.out.println(x));

list.forEach(System.out::println);

reduce()

One parameter:

@Test
public void testStreamReduce1() {
    System.out.println(list);
    BinaryOperator<String> accumulator=BinaryOperator.maxBy((x,y)->x.compareTo(y));
    Optional<String> max = list.stream()
            .reduce(accumulator);
    System.out.println(max);
}

Two parameters:

@Test
public void testStreamReduce2() {
    System.out.println(list);
    Optional<String> max = list.stream()
            .reduce((x,y)->x+y);
    System.out.println(max);
}

Three parameters:

@Test
public void testStreamReduce3() {
    System.out.println(list);
    StringBuilder joining = list.stream()
            .reduce(new StringBuilder(),
                    (x, e) -> x.append(e).append(","),
                    (u, t) -> u.append(t)
            );
    System.out.println(joining);
}

Parametric 1: The type returned, where an initial object is passed in; Parametric 2: A Funcion(x,e), x is the intermediate result of the data being processed, e is the current element. Parametric 3: Same 2.

This example is a bit complicated. Do some log analysis.

@Test
public void testStreamReduce3A() {
    System.out.println(list);
    StringBuilder joining = list.stream()
            .reduce(new StringBuilder(),
                    (x, e) -> {
                        System.out.println("2:t="+x+"; u="+e);
                        x.append(",").append(e);
                        return x;
                    },
                    (x, e) -> {
                        System.out.println("3:t="+x+"; u="+e);
                        //x.append(",").append(e);
                        return x;
                    }
            );
    System.out.println(joining);
}

You will find that the third FI has not been implemented. stream plus. parallel(), parallel processing, you see the third FI executed. But the result was a bit unexpected and messy.

There are six elements in the list, and two prints are normal six times, while three prints are only five times. And every time it runs, the print result of 3 changes.

2:t=; u=ccc
2:t=; u=eee
2:t=; u=aaa
2:t=; u=xxx
2:t=,ccc,eee,aaa; u=zzz
2:t=,ccc; u=yyy
3:t=,ccc,eee,aaa,xxx,zzz,yyy; u=,ccc,eee,aaa,xxx,zzz,yyy
3:t=,ccc,eee,aaa,xxx,zzz,yyy; u=,ccc,eee,aaa,xxx,zzz,yyy
3:t=,ccc,eee,aaa,xxx,zzz; u=,ccc,eee,aaa,xxx,zzz,yyy
3:t=,ccc,eee,aaa,xxx,zzz,yyy; u=,ccc,eee,aaa,xxx,zzz,yyy
3:t=,ccc,eee,aaa,xxx,zzz,yyy; u=,ccc,eee,aaa,xxx,zzz,yyy

count()

@Test
public void testStreamCount() {
     long count = list.stream().count();
    System.out.println(count);
}

distinct()

@Test
public void testStreamDistinct() {
    List<String> list2 = list.stream().distinct().collect(Collectors.toList());
    System.out.println(list2);
}

allMatch/anyMatch/noneMatch

@Test
public void testStreamAllMatch() {
    boolean b = list.stream().allMatch(x->x.matches("a*"));
    System.out.println("AllMath:"+b);
    b = list.stream().anyMatch(x->x.matches("a*"));
    System.out.println("anyMatch:"+b);
    b = list.stream().noneMatch(x->x.matches("a*"));
    System.out.println("noneMatch:"+b);
}

5.2)Map

Map does not support stream(), but Java 8 also adds additional checking methods to it, such as: putIfAbsent() computeIfPresent() getOrDefault() merge()

forEach

Map<String,String> map=...;
map.forEach((key,value)->System.out.pritnln("key="+key+";value="+value))

5.3) Optional

Date Time API

The Date Time API for java8 comes from jsr310( https://jcp.org/en/jsr/detail?id=310), Stephen, author of jota-time in the lead of this specification Colebourne is a quarter.

In addition to changing to thread security, it basically extends to a large extent the design style of java itself. Some convenient features of joda-time, such as Property and toString(fmt), are not introduced.

Local DateTime has limited changes compared with Calendar LocalDate copied it Copied by LocalTime Instance copied it Date Time Formatter is better than Simple Date Format. Why don't you shit? What are int Local DateTime. getDayOfMonth () and DayOfWeek dateTime.getDayOfWeek()?

@Test
    public void testClock(){
        Clock clock = null;

        clock=Clock.system(ZoneId.of("Europe/Paris"));
        System.out.println(clock.millis());

        clock=Clock.systemDefaultZone();
        long millis = clock.millis();
        System.out.println(millis);

        System.out.println(System.currentTimeMillis());

        Instant instant = clock.instant();
        Date legacyDate = Date.from(instant);
        System.out.println(legacyDate.getTime());
    }

    @Test
    public void testTimezone(){
        System.out.println(ZoneId.getAvailableZoneIds());
        ZoneId zone1 = ZoneId.of("Europe/Berlin");
        System.out.println(zone1.getRules());

        ZoneId zone2=ZoneId.of("Asia/Shanghai");
        System.out.println(zone2.getRules());
    }

    @Test
    public void testLocalDate(){
        //LocalDate is immutable
        LocalDate today = LocalDate.now();
        System.out.println(today);

        LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);

        DayOfWeek dayOfWeek = tomorrow.getDayOfWeek();
        System.out.println(dayOfWeek);
        System.out.println(dayOfWeek.getValue());
    }

    @Test
    public void testLocalTime(){
        LocalTime now1 = LocalTime.now();
        System.out.println(now1);
        LocalTime now2=now1.plusMinutes(10);
        System.out.println(now2);
        LocalTime now3=now1.plus(2, ChronoUnit.HOURS);
        System.out.println(now3);
    }

    @Test
    public void testLocalDateTime(){
        LocalDateTime dateTime=LocalDateTime.now();
        System.out.println(dateTime);
        dateTime=LocalDateTime.of(2017, 2, 22, 13, 23);
        System.out.println(dateTime);
    }

    @Test
    public void testFormater(){
        //DateTime Formatter is thread-safe, SimpleDateFormat is not.
        LocalDateTime dateTime=LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(formatter.format(dateTime));
    }

Enjoy joda-time:

System.out.println(DateTime.now().toString("yyyy-MM-dd HH:mm:ss"));
//2017-02-21 18:26:49

//Calculate how many days between the two times
DateTime dateTime=new DateTime(2008,12,8,0,0);
Duration duration=new Duration(dateTime,DateTime.now());
System.out.println(duration.getStandardDays());

//Interval can get the time difference between two times per unit
DateTime dt1 = new DateTime(2008, 12, 8, 8, 31);
DateTime dt2 = new DateTime(2017, 2, 21, 17, 21);
Interval interval = new Interval(dt1.getMillis(), dt2.getMillis());
Period p = interval.toPeriod();
System.out.println(p.toString());
System.out.println("years:" + p.getYears()+";months:"+p.getMonths()
        +";days:"+p.getDays()+";hours:"+p.getHours()
        +";minutes:"+p.getMinutes()+";seconds:"+p.getSeconds()
        +";mills:"+p.getMillis());

//Chain code
DateTime dateTime=new DateTime(2017,2,21,0,0);
System.out.println(dateTime.dayOfMonth()
    .setCopy(28)//Crossing to 2017-02-28
    .minusYears(9)//Traveling through nine years ago
    .dayOfMonth()
    .withMaximumValue()//It's the last day of that month. It's the 29th day.
    .dayOfWeek()
    //The day of get()//29 is Friday.
    .setCopy(1)//(No matter what day it is on the 29th) cross to the Monday on the 29th
    //Hello, I've been from February 2008 to 25T00:00:00.000+08:00

Repeated annotations

Before Java 8, an annotation can only be annotated once in a place, and Java 8 allows multiple annotations.

Annotation Definition:

@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
public @interface Filters {
        Filter[] value();
}

@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( Filters.class )
public @interface Filter {
        String value();
}

Annotate in Java 8:

@Filter( "filter1" )
@Filter( "filter2" )
public void sayHi(){}

The compiler implicitly adds a Filters annotation. The query annotations show that:

@com.pollyduan.annotation.Filters(value=[@com.pollyduan.annotation.Filter(value=filter1), @com.pollyduan.annotation.Filter(value=filter2)])

To achieve the same goal before that, we need to do this:

@Filters({@Filter("filter1"),@Filter("filter2")})
public void sayHi(){}

In fact, this is consistent, that is to say, the repetitive annotation of Java 8 is a grammatical sugar, and the compiler will automatically wrap it in the previous format.

VIII. Base64

Base64 is corrected in Java 8. Instead of using sun.misc.BASE64Encoder and sun.misc.BASE64Decoder, it is java.util.Base64, a factory class that creates two internal implementation classes:

Encoder encoder = Base64.getEncoder();
String str="abcd";
String enc=encoder.encodeToString(str.getBytes());
System.out.println(enc);

System.out.println(new String(Base64.getDecoder().decode(enc)));

9. Nashorn - a new javascript engine

Change of Abnormal Capture

The new try...cache can automatically close objects opened in try expressions without the need for developers to close them manually.

Multiple stream objects open statements separated by semicolons, not commas.

try(ObjectInputStream in=new ObjectInputStream(new FileInputStream("p1.obj"))){
        System.out.println(Person.class.hashCode());
        Person person=(Person)in.readObject();
        System.out.println(person.staticString);
    }  catch (Exception e) {
        e.printStackTrace();
    }
}

No longer need:

finally{
    in.close();
}

XI. nashorn

Java 8 updates the JavaScript engine, replacing the Mozilla Rhino engine introduced from jdk6 with nashorn.

To test it, first write a JS file my.js.

function myfun(str){
    return str+new Date();
}

java calls js:

package com.pollyduan.nashron;

import java.io.FileReader;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class NashornTest {

    public static void main(String[] args) throws Exception {
        ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("js");  
        nashorn.eval(new FileReader("src/main/resources/my.js"));
        Object ret = nashorn.eval("myfun(\"Hello,It\'s \")");
        System.out.println(ret);
    }
}

rhino engine is used automatically in Java 6 and 7, and nashorn engine is used automatically in Java 8.

In Java 8, it is recommended to display the specified use of nashorn:

ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");  

If a project has ever used rhino, you need to introduce dependencies and specify engineName as rhino when porting to Java 8.

<dependency>
    <groupId>cat.inspiracio</groupId>
    <artifactId>rhino-js-engine</artifactId>
    <version>1.7.7.1</version>
</dependency>

At the same time, java modification:

ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("rhino");

Summary

Java 8, which spreads all over the place. Many changes violate the original intention of object-oriented. Multiple inheritance and function pointers are available. Do you want to become c-language?

Some of the changes were positive, but the results were not satisfactory. Like date time api.

Predicate, Optional and stream are also good examples from guava.

Topics: Lambda Java JDK less