Introduction to new features of Java 8
1. Faster
2. Less code (new grammatical Lambda expressions added)
3. Powerful Stream API
4. Facilitate Parallelism
5. Optional to minimize null pointer exceptions
II. Lambda expression
1. Why use Lambda expression
Lambda is an anonymous function. We can interpret Lambda expression as a piece of code that can be passed (passing code like data). You can write more concise and flexible code. As a more compact code style, Java's language expression ability has been improved.
2. The key to Lambda expressions: the transformation from anonymous classes to Lambda
Examples:
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("hello"); } }; runnable.run(); Runnable runnable2 = () -> System.out.println("hello2"); runnable2.run();
3. Lambda expression grammar
Lambda expression introduces a new grammar element in Java language
Prime and operator. This operator is "->", which is called
For Lambda or clipping operators. It divides Lambda into
Two parts:
Left: Specifies all the parameters required for Lambda expressions
Right: Specifies the Lambda body, the Lambda expression to be executed
Functions.
(1) Grammar Format 1: No parameter, no return value, Lambda body only needs one statement
Examples:
Runnable r1 = () -> System.out.println("Hello Lambda!");
(2) Grammar Format 2: Lambda needs a parameter.
Examples:
Consumer<String> con = (x) -> System.out.println(x);
(3) Grammatical Format 3: When Lambda only needs one parameter, parentheses of parameters can be omitted.
Examples:
Consumer<String> con = x -> System.out.println(x);
(4) Syntax Format 4: Lambda requires two parameters and has a return value.
Examples:
Comparator<Integer> com = (x, y) -> { System.out.println("Functional interface"); return Integer.compare(x, y); };
(5) Grammatical Format 5: When Lambda has only one sentence, return and braces can be omitted.
Examples:
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
(6) The data type of the parameter list of Lambda expression can be omitted because the JVM compiler infers the data type by context, that is, "type inference".
Examples:
Comparator<Integer> com = (Integer x,Integer y) -> {//Integer types can be omitted System.out.println("Functional interface"); return Integer.compare(x, y); };
Eliminate parameter types:
Comparator<Integer> com = (x,y) -> { System.out.println("Functional interface"); return Integer.compare(x, y); };
Type inference: The parameter types in Lambda expressions are inferred by the compiler. There is no need to specify a type in a Lambda expression, and the program can still be compiled because javac infers the type of parameter in the background based on the context of the program. The type of Lambda expression depends on the context and is inferred by the compiler. This is what is called "type inference"
3. Functional Interface
1. What is a functional interface?
(1) An interface containing only one abstract method is called a functional interface.
(2) You can create the object of the interface by Lambda expression. (If the Lambda expression throws a checked exception, the exception needs to be declared in the abstract method of the target interface).
(3) We can use the @Functional Interface annotation on any functional interface to check whether it is a functional interface, and javadoc will include a declaration that the interface is a functional interface.
2. Custom Function Interface
@FunctionalInterface public interface TestMyFunction { public double getValue(); }
Generics are used in functional interfaces:
@FunctionalInterface public interface TestMyFunction<T> { public T getValue(T t); }
3. Lombarda expression passed as a parameter
public String toUpperString(TestMyFunction<String> mf,String str) { return mf.getValue(str); }
The lambda expression passed as a parameter:
String newStr = toUpperString((str) -> str.toUpperCase(),"abc"); System.out.println(newStr);
Transfer Lambda expression as a parameter: In order to transfer Lambda (TestMyFunction < String > mf) expression as a parameter, the parameter type of receiving Lambda expression must be a functional interface compatible with the Lambda expression.
Type.
4. Java Built-in Four Core Functional Interfaces
(1) Consumer < T >: Consumer Interface
void accept(T t);
Examples:
//Consumer < T > Consumer Interface: @Test public void test1() { happy(10000, (m) -> System.out.println("You guys like big swords, every time they consume:" + m + "element")); } public void happy(double money, Consumer<Double> con) { con.accept(money); }
(2) Supplier < T >: Supply-type interface T get();
Examples:
//Supplier < T > Supply Interface: @Test public void test2() { List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100)); for (Integer num : numList) { System.out.println(num); } } //Requirement: Generate a specified number of integers and put them into the collection public List<Integer> getNumList(int num, Supplier<Integer> sup) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer n = sup.get(); list.add(n); } return list; }
(3) Function < T, R >: Functional interface R apply (T);
Examples:
@Test public void test3() { String newStr = strHandler("\t\t\t I believe in Silicon Valley's mighty power ", (str) -> str.trim()); System.out.println(newStr); String subStr = strHandler("I believe in Silicon Valley's mighty power", (str) -> str.substring(2, 5)); System.out.println(subStr); } // Requirements: For processing strings public String strHandler(String str, Function<String, String> fun) { return fun.apply(str); }
(4) Predicate < T >: assertive interface Boolean test (T);
Examples:
//Predicate < T > assertive interface: @Test public void test4() { List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok"); List<String> strList = filterStr(list, (s) -> s.length() > 3); for (String str : strList) { System.out.println(str); } } // Requirement: Put qualified strings into a collection public List<String> filterStr(List<String> list, Predicate<String> pre) { List<String> strList = new ArrayList<>(); for (String str : list) { if (pre.test(str)) { strList.add(str); } } return strList; }
5. Other interfaces
6. Method reference and constructor reference
Method references:
When the operation to be passed to the Lambda body is already implemented, method references can be used!
(To implement the parameter list of an abstract method, it must be consistent with the parameter list of the method referenced!)
Method Reference: Use the operator ":" to separate the method name from the name of the object or class.
The following three main uses:
(1) Object: Instance method
For example:
@Test public void test1() { PrintStream ps = System.out; Consumer<String> con = (str) -> ps.println(str); con.accept("Hello World!"); System.out.println("--------------------------------"); Consumer<String> con2 = ps::println; con2.accept("Hello Java8!"); Consumer<String> con3 = System.out::println; } @Test public void test2() { Employee emp = new Employee(101, "Zhang San", 18, 9999.99); Supplier<String> sup = () -> emp.getName(); System.out.println(sup.get()); System.out.println("----------------------------------"); Supplier<String> sup2 = emp::getName; System.out.println(sup2.get()); }
(2) Class: Static methods
For example:
@Test public void test() { BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y); System.out.println(fun.apply(1.5, 22.2)); System.out.println("--------------------------------------------------"); BiFunction<Double, Double, Double> fun2 = Math::max; System.out.println(fun2.apply(1.2, 1.5)); } @Test public void test4() { Comparator<Integer> com = (x, y) -> Integer.compare(x, y); System.out.println("-------------------------------------"); Comparator<Integer> com2 = Integer::compare; }
(3) Class: Instance method
For example:
@Test public void test5() { BiPredicate<String, String> bp = (x, y) -> x.equals(y); System.out.println(bp.test("abcde", "abcde")); System.out.println("-----------------------------------------"); BiPredicate<String, String> bp2 = String::equals; System.out.println(bp2.test("abc", "abc")); System.out.println("-----------------------------------------"); Function<Employee, String> fun = (e) -> e.show(); System.out.println(fun.apply(new Employee())); System.out.println("-----------------------------------------"); Function<Employee, String> fun2 = Employee::show; System.out.println(fun2.apply(new Employee())); }
Be careful:
* The parameter list and return value type of the method referenced by the method need to be consistent with the parameter list and return value type of the abstract method in the functional interface.
* (2) If the first parameter of Lambda's parameter list is the caller of the instance method and the second parameter (or no parameter) is the parameter of the instance method, the format is ClassName::MethodName.
Constructor Reference: The parameter list of the constructor needs to be consistent with the parameter list in the functional interface!
Format: ClassName::new
Combining with functional interface, it is automatically compatible with methods in functional interface.
Constructor references can be assigned to defined methods, and constructor parameters
The list should be consistent with the parameter list of the abstract method in the interface!
Function<Integer,MyClass> fun = (n) -> new MyClass(n); //Equivalent to Function<Integer,MyClass> fun2 = MyClass::new;
Array reference:
Format: type []::new
Function<Integer,Integer[]> fun = (n) -> new Integer[n]; //Equivalent to Function<Integer,Integer[]> fun2 = Integer[]::new;