New feature of Java 8 - Lambda expression

Keywords: Programming Lambda Java less jvm

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;

Posted by rdub on Wed, 24 Jul 2019 00:59:45 -0700