[Java Advanced Programming] New Features of Java8

insert image description here

1. Overview of the new features of Java8

  • functional interface
  • Lambda expression
  • method reference/constructor reference
  • Stream API
    • parallel stream
    • serial stream
  • Interface enhancements
    • static method
    • default method
  • Optional class
  • New time and date API
  • Other new features
    • Duplicate annotation
    • type annotation
    • Generic Object Type Inference
    • Update of JDK
      • Streaming operations on collections
      • concurrency
      • Arrays
      • Number and Math
      • IO/NIO Improvements
      • Reflection gets the formal parameter name
      • String:join()
      • Files
    • New compilation tools: jjs, jdeps
    • Metaspace replaces PermGen space in JVM

2. Lambda expression

2.1. Comparison before and after the use of Lambda expressions

@Test
public void test1 () {
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("我爱北京天安门");
        }
    };
    r1.run();
    // 使用lambda表达式
    Runnable r2 = () -> System.out.println("我爱北京天安门");
    r2.run();
}
@Test
public void test2 () {
    Comparator<Integer> com1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    System.out.println(com1.compare(12, 21));
    // Lambda表达式的写法
    Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
    System.out.println(com2.compare(32, 21));
    // 方法引用
    Comparator<Integer> com3 = Integer :: compare;
    System.out.println(com3.compare(32, 21));
}

2.2. Basic grammar of Lambda expression

  • Example: (o1, o2) -> Integer.compare(o1, o2);
  • Format:
    • ->: lambda operator or arrow operator
    • -> Left: lambda formal parameter list (actually the formal parameter list of the abstract method in the interface)
    • -> Right: lambda body (actually the method body of the rewritten abstract method)

2.3, how to use: divided into six situations

  • Grammar format 1: no parameter, no return value
    • Runnable r1 = () -> {System.out.println("Hello Lambda!");};
  • Grammar format 2: Lambda requires a parameter, but has no return value
    • Consumer<String> con = (String str) -> {System.out.println(str);};
  • Syntax format 3: The data type can be omitted because it can be inferred by the compiler, which is called "type inference"
    • Consumer<String> con = (str) -> {System.out.println(str);};
  • Grammar format 4: If Lambda only needs one parameter, the parentheses of the parameter can be omitted
    • Consumer<String> con = str -> {System.out.println(str);};
  • Grammar format five: Lambda requires two or more parameters, multiple execution statements, and can have a return value
    • Comparator<Integer> com = (x, y) -> {System.out.println("实现函数式接口方法!"); return Integer.compare(x, y);};
  • Grammar format 6: When the Lambda body has only one statement, return and curly braces, if present, can be omitted
    • Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

Summarize six situations:
-> left: the parameter type of the lambda parameter list can be omitted (type inference); if the lambda parameter list has only one parameter, the pair () can also be omitted -> right: the lambda body should use
a pair {} package; if the lambda body has only one execution statement (probably a return statement, omit the pair of {} and return keywords)

3. Functional interface

3.1. Instructions for using the functional interface

  • If an interface declares only one abstract method, the interface is called a functional interface
  • We can annotate an interface with @FunctionalInterface and in doing so we can check if it is a functional interface
  • The Essence of Lambda Expressions: As Instances of Functional Interfaces

3.2. Four basic functional interfaces provided by Lambda expressions in Java8

functional interface Parameter Type return type use
Consumer<T>consumer interface T void Apply an operation to an object of type T, including the method: void accept(T t)
Supplier<T>supply interface none T Returns an object of type T, including the method: T get()
Function<T, R>functional interface T R Applies an operation to an object of type T, and returns the result. The result is an object of type R. Include method: R apply(T t)
Predicate<T>assertion interface T boolean Determines whether an object of type T satisfies a constraint, and returns a boolean value. Contains method: boolean test(T t)

3.3. Summary

  • When to use lambda expressions?
    • When you need to instantiate a functional interface, you can use lambda expressions
  • When to use a given functional interface?
    • If we need to define a functional interface during development, first check whether the functional interface provided by the existing JDK provides a functional interface that can meet the requirements. If there is, you can call it directly, and you don’t need to customize it yourself.

4. Method reference

4.1. Understanding

  • Method reference can be regarded as a deep expression of Lambda expression. In other words, a method reference is a Lambda expression, which is an instance of a functional interface, pointing to a method by its name.

4.2. Usage scenarios

  • When the operation to be passed to the Lambda body already has an implemented method, you can use the method reference

4.3. Format

  • class (or object) :: method name

4.4, divided into the following three situations

  • Object:: non-static method --> Case 1
  • class:: static method --> case 2
  • class:: non-static method --> case 3

4.5. Requirements

  • The formal parameter list and return value type of the abstract method in the interface are required to be the same as the formal parameter list and return value type of the method referenced by the method! (for case 1 and case 2)
  • When the first parameter of the functional interface method is the caller that needs to refer to the method, and the second parameter is the parameter (or no parameter) that needs to refer to the method: ClassName::methodName (for case 3)

4.6. Suggestions for use

  • If providing an instance for a functional interface just satisfies the usage scenario of a method reference, you can consider using a method reference to provide an instance for a functional interface. If you are not familiar with method references, you can also use lambda expressions.

4.7. Examples of use

// 情况一:对象 :: 实例方法
// Consumer中的void accept(T t)
// PrintStream中的void println(T t)
@Test
public void test1 () {
    Consumer<String> con1 = str -> System.out.println(str);
    con1.accept("北京");
    // 方法引用
    PrintStream ps = System.out;
    Consumer<String> con2 = ps::println;
    con2.accept("beijing");
}
// 情况二:类 :: 静态方法
// Comparator中int compare(T t1, T t2)
// Integer中的int compare(T t1, T t2)
@Test
public void test3 () {
    Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
    System.out.println(com1.compare(12,21));
    // 方法引用
    Comparator<Integer> com2 = Integer::compare;
    System.out.println(com2.compare(12, 3));
}
// 情况三:类 :: 实例方法
// Comparator中的int compare(T t1, T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5 () {
    Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
    System.out.println(com1.compare("abc", "abd"));
    // 方法引用
    Comparator<String> com2 = String :: compareTo;
    System.out.println(com2.compare("adb", "abm"));
}

5. Constructor reference and array reference

5.1. Constructor reference format

  • classname::new

5.2. Constructor reference usage requirements

  • Similar to method references, the formal parameter list of an abstract method of a functional interface is the same as the formal parameter list of a constructor. The return value type of an abstract method is the type of the class to which the constructor belongs

5.3. Examples of constructor references

// 构造器引用
// Supplier的T get()
// Employee的空参构造器:Employee()
@Test
public void test1 () {
    Supplier<Employee> sup = new Supplier<Employee>() {
        @Override
        public Employee get() {
            return new Employee();
        }
    };
    // lambda表达式
    Supplier<Employee> sup1 = () -> new Employee();
    System.out.println(sup1.get());
    // 构造器引用
    Supplier<Employee> sup2 = Employee :: new;
    System.out.println(sup2.get());
}
// Function中的R apply(T t)
@Test
public void test2 () {
    Function<Integer, Employee> func1 = id -> new Employee(id);
    System.out.println(func1.apply(1001));
    // 构造器引用
    Function<Integer, Employee> func2 = Employee :: new;
    System.out.println(func2.apply(1002));
}

5.4. Array reference format

  • ArrayType[]::new

5.5. Examples of array references

// 数组引用
// Function中的R apply(T t)
@Test
public void test4 () {
    Function<Integer, String[]> func1 = length -> new String[length];
    System.out.println(Arrays.toString(func1.apply(5)));
    // 数组引用
    Function<Integer, String[]> func2 = String[] :: new;
    System.out.println(Arrays.toString(func2.apply(10)));
}

6、Stream API

6.1. Understanding of Stream API

  • Stream focuses on the operation of data and deals with CPU; collection focuses on data storage and deals with memory
  • Java 8 provides a set of APIs, which can be used to filter, sort, map, reduce and other operations on data in memory. Similar to SQL related operations on tables in the database.

6.2, Notes

  • Stream itself does not store elements
  • Stream does not mutate the source object. Instead, they return a new Stream holding the result
  • Stream operations are performed lazily. This means they wait until the result is needed to execute

6.3, Stream usage process

  • Stream instantiation
  • A series of intermediate operations (filtering, mapping, ...)
  • terminate operation

6.4. Points to note when using the process

  • An intermediate operation chain to process the data of the data source
  • Once the terminating operation is executed, the chain of intermediate operations is executed and results are produced. After that, it will not be used again.

6.5. Step 1: Stream instantiation

// 创建Stream方式一:通过集合
@Test
public void test1 () {
    List<Employee> employees = EmployeeData.getEmployees();
    // default Stream<E> stream():返回一个顺序流
    Stream<Employee> stream = employees.stream();
    // default Stream<E> parallelStream():返回一个并行流
    Stream<Employee> parallelStream = employees.parallelStream();
}
// 创建Stream方式二:通过数组
@Test
public void test2 () {
    int[] arr = new int[]{1,2,3,4,5,6};
    // 调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
    IntStream stream = Arrays.stream(arr);
}
// 创建Stream方式三:通过Stream的of()
@Test
public void test3 () {
    Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
// 创建Stream方式四:创建无限流
@Test
public void test4 () {
    // 迭代
    // public static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    // 遍历前10个偶数
    Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
    // 生成
    // public static <T> Stream<T> generate(Supplier<T> s)
    Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

6.6. Step 2: Intermediate Operation

  • Screening and Slicing
    • filter(Predicate p): Receive Lambda, exclude certain elements from the stream
    • distinct(): filter, remove duplicate elements through hashCode() and equals() of the elements generated by the stream
    • limit(long maxSize): truncate the stream so that its elements do not exceed the given number
    • skip(long n): Skip elements and return a stream with the first n elements thrown away. If there are less than n elements in the stream, an empty stream is returned. Complementary to limit(n)
  • map
    • map(Function f): Receives a function as a parameter, which will be applied to each element and mapped into a new element
    • mapToDouble(ToDoubleFunction f): Receives a function as a parameter, which will be applied to each element to generate a new DoubleStream
    • mapToInt(ToIntFunction f): Receives a function as a parameter, which will be applied to each element to generate a new IntStream
    • mapToLong(ToLongFunction f): Receives a function as a parameter, which will be applied to each element to generate a new LongStream
    • flatMap(Function f): Receives a function as a parameter, replaces each value in the stream with another stream, and then concatenates all streams into one stream
  • to sort
    • sorted(): Produces a new stream, which is sorted in natural order
    • sorted(Comparator com): yields a new stream sorted in comparator order

6.7. Step 3: Terminate the operation

  • match and find
    • allMatch(Predicate p): checks whether all elements are matched
    • anyMatch(Predicate p): checks if at least one element is matched
    • noneMatch(Predicate p): checks whether all elements are not matched
    • findFirst(): returns the first element
    • findAny(): returns any element in the current stream
    • count(): returns the total number of elements in the stream
    • max(Comparator c): returns the maximum value in the stream
    • min(Comparator c): returns the minimum value in the stream
    • forEach(Consumer c): internal iteration (using the Collection interface requires the user to iterate, which is called external iteration. On the contrary, the Stream API uses internal iteration-it does the iteration for you)
  • reduction
    • reduce(T iden, BinaryOperator b): The elements in the stream can be combined repeatedly to obtain a value. return T
    • reduce(BinaryOperator b): The elements in the stream can be combined repeatedly to obtain a value. returnOptional<T>
  • collect
    • collect(Collector c): convert the stream into other forms. Receive an implementation of the Collector interface, which is used to summarize the elements in the Stream (Collector provides instances through Collectors)
      • toList()
      • toSet()
      • toCollection()

7. Use of Optional class

7.1. Understanding

  • Born to solve the problem of null pointers in Java!
  • Optional<T>The class (java.util.Optional) is a container class that can hold a value of type T, representing the existence of this value. Or just store null, indicating that the value doesn't exist. In the past, null was used to indicate the absence of a value, but now Optional can better express this concept. And can avoid null pointer exception.

7.2 Common methods

@Test
public void test1 () {
    
    
    // empty():创建的Optional对象内部的value = null
    Optional<Object> op1 = Optional.empty();
    if (!op1.isPresent()) {
    
    
        // Optional封装的数据是否包含数据
        System.out.println("数据为空");
    }
    // 如果Optional封装的数据value为空,则get()报错。否则,value不为空时,返回value
    // System.out.println(op1.get());
}
@Test
public void test2 () {
    
    
    String str = "hello";
    // of(T t):封装数据t生成Optional对象,要求t非空,否则报错
    Optional<String> op1 = Optional.of(str);
    // get()通常与of()方法搭配使用。用于获取内部的封装的数据value
    String str1 = op1.get();
    System.out.println(str1);
}
@Test
public void test3 () {
    
    
    String str = "beijing";
    str = null;
    // ofNullable(T t):封装数据t赋给Optional内部的value。不要求t非空
    Optional<String> op1 = Optional.ofNullable(str);
    // orElse(T t1):如果Optional内部的value非空,则返回此value值。如果value为空,则返回t1
    String str2 = op1.orElse("shanghai");
    System.out.println(str2);
}

Guess you like

Origin blog.csdn.net/qq_51808107/article/details/131448546