Java 8 (also known as jdk 1.8) was released by oracle in March 2014. It can be regarded as the most revolutionary version since Java 5. Java 8 brings a lot of new features to the Java language, compiler, class library, development tools and JVM.
1, Lambda expression
Let's look at two examples:
@Test public void test01(){ Runnable r1 = new Runnable() { @Override public void run() { System.out.println("I love Java..."); } }; r1.run();//Just run the overridden run() method, not multithreading //Using Lambda expressions Runnable r2 = () -> {System.out.println("I love Java 8 New features...");}; r2.run(); }
@Test public void test02(){ Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; int compare = comparator.compare(30, 28); System.out.println(compare);//1 //Using Lambda expressions Comparator<Integer> comparator1 = (o1,o2) -> compare(o1,o2); int compare1 = comparator1.compare(25, 36); System.out.println(compare1); //Method reference Comparator<Integer> comparator2 = Integer::compare; int compare2 = comparator2.compare(22, 36); System.out.println(compare2); }
Lambba is an anonymous function. Lambda can be understood as a piece of code that can be passed (pass the code like data). As can be seen from the example, lambda has a fixed format:
Example: (o1, o2) - > integer. Compare (o1, o2)
Format:
->: Lambda operator
(): Lambda formal parameter list (in fact, it is the formal parameter list of abstract methods in the interface)
{}: Lambda body (actually the method body of the overridden abstract method)
Lambda essence: as an example of functional interface
1. Syntax format 1: no parameter and no return value
@Test public void test01(){ Runnable r1 = new Runnable() { @Override public void run() { System.out.println("I love Java..."); } }; r1.run();//Just run the overridden run() method, not multithreading //Syntax format 1: no parameter and no return value Runnable r2 = () -> System.out.println("I love Java 8 New features..."); r2.run(); }
2. Syntax format 2: Lmabda has a parameter and no return value
@Test public void test02(){ Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("study hard Java programming..."); //Syntax format 2: Lambda expression has a parameter and no return value Consumer<String> consumer1 = (String s) -> { System.out.println(s); }; consumer1.accept("You can make a lot of money in the future..."); }
3. Syntax format 3: data types can be omitted and can be exited by the compiler, which is called "type inference"
@Test public void test03(){ Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("study hard Java programming..."); //Syntax format 3: data types can be omitted and can be exited by the compiler, which is called "type inference" Consumer<String> consumer1 = (s) -> { System.out.println(s); }; consumer1.accept("Eat delicious food every day..."); }
4. Syntax format 4: there is only one parameter, and the parentheses of the parameter can be omitted
@Test public void test04(){ Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("study hard Java programming..."); //Syntax format 4: there is only one parameter, and the parentheses of the parameter can be omitted Consumer<String> consumer1 = s -> { System.out.println(s); }; consumer1.accept("Live in a big house in the future..."); }
5. Syntax format 5: Lambda has more than two parameters, multiple execution statements and return values
@Test public void test05(){ Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); } }; System.out.println(comparator.compare(25,26)); System.out.println(); //Syntax format 5: Lambda has more than two parameters, multiple execution statements and return values Comparator<Integer> comparator1 = (Integer o1,Integer o2) -> {System.out.println(o1); System.out.println(o2); return o1.compareTo(o2); }; System.out.println(comparator1.compare(12,5)); }
6. Syntax format 6: Lambda expression has an execution statement. return and {} if any, can be omitted
@Test public void test06(){ Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; System.out.println(comparator.compare(25,26)); System.out.println(); //Syntax format 6: Lambda expression has an execution statement. return and {} if any, can be omitted Comparator<Integer> comparator1 = (Integer o1,Integer o2) -> o1.compareTo(o2); System.out.println(comparator1.compare(12,5)); }
Lambda expression summary:
->Left (): parameter types in Lambda's formal parameter list can be omitted (type inference). If there is only one formal parameter, then () can also be omitted
->On the right {}: the Lamdba body is enclosed by a pair of {}. If there is only one execution statement in {}, the parentheses can be omitted, and the return keyword can also be omitted.
2, Functional interface
If only one abstract method is declared in an interface, the interface is called a functional interface.
Lambda expressions, method references, constructor references, and array references are all regarded as instances of functional interfaces.
Use the annotation @ functional interface to identify checks, such as Consumer, Runnable, Comparator, etc.
@Test public void test01(){ happyTime(200.0, new Consumer<Double>() { @Override public void accept(Double aDouble) { System.out.println("Flying to Shanghai to buy Nongfu mountain spring cost:"+aDouble); } }); System.out.println(); happyTime(300.0,money -> System.out.println("Flying to Hainan to buy Nongfu mountain spring cost:"+money)); } public void happyTime(Double money, Consumer<Double> cons){ cons.accept(money); }
@Test public void test02(){ List<String> list = Arrays.asList("Beijing", "Nanjing", "the Western Capital", "Tokyo", "Tianjin"); List<String> arrayList = fielterString(list, new Predicate<String>() { @Override public boolean test(String s) { return s.contains("Beijing"); } }); System.out.println(arrayList.toString()); List<String> fielterString = fielterString(list, s -> s.contains("Beijing")); System.out.println(fielterString.toString()); } public List<String> fielterString(List<String> list, Predicate<String> pre){ ArrayList<String> arrayList = new ArrayList<>(); for(String s : list){ if(pre.test(s)){ arrayList.add(s); } } return arrayList; }
3, Method reference
671
A method reference is a lambda expression. Lambda is an instance of a functional interface, so a method reference is an instance of a functional interface
Requirements for method reference: the parameter list and return value type of the abstract method implementing the interface must be consistent with the parameter list and return value type of the method referenced by the method!
Format: class (or object): method name
There are three main cases of method reference
1. Object: non static method
@Test public void test01(){ //1. Functional interfaces are generally used Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) {//Void accept in Consumer System.out.println(s); } }; consumer.accept("Beijing"); //2.Lambda expression Consumer<String> consumer1 = s -> System.out.println(s); consumer1.accept("the Western Capital"); //3. Method reference PrintStream ps = System.out;//Out. Println in System Consumer<String> consumer2 = ps::println; consumer2.accept("Nanjing"); }
2. Class: static method
@Test public void test02(){ //1. Functional interfaces are generally used Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) {//Int compare in Comparator (t T1, t T2) return Integer.compare(o1,o2); } }; System.out.println(comparator.compare(25, 26));//Output return value - 1 //2.Lambda expression Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1,o2); System.out.println(comparator1.compare(35,26));//1 //3. Method reference Comparator<Integer> comparator2 = Integer::compare;//Int compare in Integer (t T1, t T2) System.out.println(comparator2.compare(23,52));//-1 }
3. Class: non static method
@Test public void test03(){ //1. Functional interfaces are generally used Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }; System.out.println(comparator.compare("abs","abc")); //2.Lambda expression Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2); System.out.println(comparator1.compare("abc","abd"));//Int compare in Comparator (t T1, t T2) //3. Method reference Comparator<String> comparator2 = String::compareTo;//int t1.compareTo(t2) in String System.out.println(comparator2.compare("abd","abc")); }
5, Constructor reference
Constructor reference is lambda expression. Lambda is an instance of functional interface, so method reference is also an instance of functional interface
Similar to method references, the formal parameter list of abstract methods of functional interfaces is consistent with that of constructors. The return value type of the abstract method is the type of the class to which the constructor belongs.
/** * Constructor reference test class * @author wds * @date 2021-12-01-10:02 */ public class ReflectionTest { //Constructor reference //T get in Supplier //Null parameter constructor in Customer: Customer() @Test public void test01(){ Supplier<Customer> supplier = new Supplier<Customer>() { @Override public Customer get() { return new Customer(); } }; System.out.println(supplier.get()); Supplier<Customer> supplier1 = () -> new Customer(); System.out.println(supplier1.get()); Supplier<Customer> supplier2 = Customer::new; System.out.println(supplier2.get()); } //R apply in Function (T) //Constructor of one parameter in Customer: Customer(int age) @Test public void test02(){ Function<Integer,Customer> function = new Function<Integer, Customer>() { @Override public Customer apply(Integer age) { return new Customer(age); } }; System.out.println(function.apply(19)); Function<Integer,Customer> function1 = age -> new Customer(age); System.out.println(function1.apply(16)); Function<Integer,Customer> function2 = Customer::new; System.out.println(function2.apply(17)); } //Apply in BiFunction (T, t, U) //Constructor of two parameters in Customer: Customer(String name,int age) @Test public void test03(){ BiFunction<String,Integer,Customer> biFunction = new BiFunction<String, Integer, Customer>() { @Override public Customer apply(String name, Integer age) { return new Customer(name,age); } }; System.out.println(biFunction.apply("Xiao Wang",19)); BiFunction<String,Integer,Customer> biFunction1 = (name,age) -> new Customer(name,age); System.out.println(biFunction1.apply("Xiao LV",17)); BiFunction<String,Integer,Customer> biFunction2 = Customer::new; System.out.println(biFunction2.apply("Xiao Zhang",20)); } } class Customer { private String name; private int age; public Customer() { } public Customer(int age) { this.age = age; } public Customer(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Customer{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
test01() test results
test02() test results
test03() test results
6, Array reference
Array reference can be regarded as a special case of constructor reference. In fact, it is to create an array. The first parameter is array length and the second parameter is array data type.
@Test public void test(){ //1. General usage of functional interface Function<Integer,String[]> function = new Function<Integer, String[]>() { @Override public String[] apply(Integer length) { return new String[length]; } }; String[] arr = function.apply(5); System.out.println(Arrays.toString(arr)); //2.Lambda expression Function<Integer,String[]> function1 = length -> new String[length]; String[] arr1 = function1.apply(6); System.out.println(Arrays.toString(arr1)); //3. Array reference Function<Integer,String[]> function2 = String[] :: new; String[] arr2 = function2.apply(7); System.out.println(Arrays.toString(arr2)); }