Chapter I functional interface
1.1 concept
Functional interface in java refers to an interface with only one abstract method
Functional interface, that is, the interface suitable for functional programming scenarios. The embodiment of functional programming in java is Lambda, so functional interface is the interface that can be used by Lambda. Only by ensuring that there is only one abstract method in the interface can Lambda in java be deduced smoothly.
Note: "syntax sugar" refers to the code syntax that is more convenient to use, but the principle remains the same. For example, when traversing a collection, the underlying implementation principle of the for each syntax is still the iterator, which is the "syntax sugar". From the application level, lambda in java can be regarded as the "syntax sugar" of anonymous inner classes, but they are different in principle (anonymous inner classes will generate new class files when compiling, but lambda will not).
1.2 format
Just make sure there is only one abstract method in the interface:
Modifier interface Interface name{ public abstract Return value type method name(Optional parameter information); //The preceding modifier can be omitted //Content of other non abstract methods (default, static, private) }
1.3 @FunctionalInterface annotation
Similar to the @ override annotation, Java 8 introduces a new annotation @ FunctionalInterface. For functional interfaces This annotation can be used for the definition of an interface:
@FunctionalInterface public interface YourFather { void method();//An abstract method is defined }
Function: it will automatically detect whether your interface conforms to the definition of functional interface. If it does not (there is no abstract method or more than one in the interface), the annotation will report an error
1.4 user defined functional interface and use
Custom functional interface
@FunctionalInterface public interface YourFather { void method();//An abstract method is defined }
Implementation class of interface
public class YourFatherC implements YourFather { @Override public void method() { System.out.println("I'm your father"); } }
use
- Can be used as a parameter of a method
public class Main { //As a parameter public static void show(YourFather yourFather){ yourFather.method(); } public static void main(String[] args) { //Call the show method. The parameter of the method is an interface, so the implementation class object of the interface can be passed show(new YourFatherC()); //Anonymous Inner Class show(new YourFather() { @Override public void method() { System.out.println("I'm your father"); } }); //You can use Lambda show(()-> System.out.println("I'm your father")); } }
Chapter II functional programming
2.1 delayed execution of lambda
After the code of some scenarios is executed, the results may not be used, resulting in a waste of line energy Lambda expressions are delayed, which can be used as a solution to improve performance
Log cases of performance waste
Note: logs can help us quickly locate problems and record the situation during the operation of the program, so as to facilitate the monitoring and optimization of the project
A typical scenario is to conditionally use parameters. For example, after splicing log messages, print out when the conditions are met:
package demo09; //Log case public class Main { //Define a method to display log information according to the level of the log public static void showLog(int level, String message) { //Judge the level of the log if (level == 1) { System.out.println(message); } } public static void main(String[] args) { //We define three log information in the main method String msg1 = "I'm your father"; String msg2 = "World"; String msg3 = "Java"; //Call showLo method and pass the write parameter showLog(2, msg1 + msg2 + msg3); } }
We will find that there are some problems that can be wasted
- He should first splice the second parameter and judge the level
- If the level does not match, then the splicing is wasted
So We use Lambda expression to optimize this case (optimization premise: there must be a functional interface)
//Functional interface package demo09; @FunctionalInterface public interface MessageBuilder { //Define a method to splice strings String stringBuilder(); } //Main function package demo09; //Lambda features: delayed loading //Premise of use: there must be a functional interface public class Lambda { //Define a method to display logs public static void showLog(int level, MessageBuilder mb) { //Judge the level of the log if (level == 1) { System.out.println(mb.stringBuilder()); } } public static void main(String[] args) { //We define three log information in the main method String msg1 = "I'm your father"; String msg2 = "World"; String msg3 = "Java"; //Call showLo method and pass the write parameter showLog(2, () -> (msg1 + msg2 + msg3)); } }
After using Lambda, the Lambda expression is passed as a parameter, just passing the parameter to the showLog method
- When the conditions are met, the rewritten method in Lambda will be called for string splicing
- If the conditions are not met, the rewritten method will not execute and will not waste performance
2.2 use Lambda as parameter and return value
Regardless of the implementation principle, Lambda expressions in Java can be regarded as an alternative to anonymous inner classes If the parameter of a method is a functional interface type, you can use Lambda expression as the method parameter. In fact, you can use functional interface as the method parameter
I used this method in the last section. Just have a look
Similarly, if the return value type of a method is a functional interface, you can directly return a Lambda expression When you need a method to get a Java util. When an object of comparator interface type is used as a sorter, this method can be called to obtain
package demo09; import java.util.Arrays; import java.util.Comparator; public class Lambda { private static Comparator<String> newComparator() { return (a,b) -> b.length() - a.length();//In ascending order, the return value is int } public static void main(String[] args) { String[] arr = {"Your father","Your father","Your grandfather"}; System.out.println(Arrays.toString(arr)); Arrays.sort(arr,newComparator()); System.out.println(Arrays.toString(arr)); } }
Chapter III common functional interfaces
JDK provides a large number of commonly used functional interfaces to enrich the typical usage scenarios of Lambda, mainly in Java util. Function package is provided
3.1 Supplier interface
java. util. function. The supplier < T > interface only contains a parameterless method T get() to obtain object data of the type specified by a generic parameter. Because this is a functional interface, it means that the corresponding Lambda expression needs to "provide" an object data conforming to the generic type
package demo09; // The supplier < T > interface is called a production interface. It specifies what type the generic type of the interface is, and what type the get() method in the interface will return import java.util.function.Supplier; public class Lambda { public static void method(Supplier<String> sup){ System.out.println(sup.get());//The return value type of get is determined by the generic type of the interface parameter in the method parameter } public static void main(String[] args) { method(() -> "I'm your father"); } }
3.2 exercise: find the maximum value of array elements
Title:
Using the Supplier interface as the method parameter type, find the maximum value in the int array through the Lambda expression Tip: please use Java. Com for interface generics Lang. integer class
answer
package demo09; // The supplier < T > interface is called a production interface. It specifies the type of the generic type of the interface, and the type returned by the get() method in the interface import java.util.function.Supplier; public class Lambda { public static int getMax(int[] arr,Supplier<Integer> sup){ return sup.get(); } public static void main(String[] args) { int[] arr = {123,444,2,66,8565}; int maxNum = getMax(arr,() -> { int max = arr[0]; for (int i : arr) { if (max < i){ max = i; } } return max; }); System.out.println(maxNum); } }
3.3 Consumer interface
java. util. function. The consumer < T > interface is just opposite to the Supplier interface. Instead of generating a data, it consumes a data. The data type is determined by generics
How to consume specifically needs to be customized (output, calculation, etc.)
Abstract method: accept
The Consumer interface contains the abstract method void accept (T), which means to consume data of a specified generic type Basic usage, such as:
package demo09; import java.util.function.Consumer; public class Lambda { private static void method(String name, Consumer<String> con){ con.accept(name); } public static void main(String[] args) { method("Sweet shit",(name) -> { String newName = new StringBuilder(name).reverse().toString(); System.out.println(newName); });//Output print result: excrement is really fragrant } }
Default method: andThen
If the parameters and return values of a method are of Consumer type, the effect can be achieved: when consuming data, first do an operation, and then do an operation to realize combination
This method is the default method andThen in the Consumer interface The following is the JDK source code
default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); };//This is the lambda format of the accept method }
Note: objects The requirenonnull () method detects whether the parameter is null. If so, it will actively throw a NullPointerException exception This eliminates the trouble of writing and throwing null pointer exceptions
To realize composition, you need two or more Lambda expressions. The semantics of andThen is a step-by-step operation For example, when two steps are combined
package demo09; import java.util.function.Consumer; public class Lambda { private static void method(String name, Consumer<String> con1, Consumer<String> con2) { // con1.accept(name); // con2.accept(name); con1.andThen(con2).accept(name);//This sentence means the above two sentences } public static void main(String[] args) { method("Hello World" , (name) -> { System.out.println(name.toLowerCase()); }, (name) -> System.out.println(name.toUpperCase())); } }
3.4 format and print information
subject
There are multiple pieces of information in the following string array. Please print the information in the format of "Name: XX gender: XX" It is required to take the action of printing name as the Lambda instance of the first consumer interface and the action of printing gender and amount as the Lambda instance of the second consumer interface, and splice the two interfaces together in order
public static void main (String[] args) { String[] array = {"Delireba,female","Gulinaza,female","Ma erzaha,male"}; }
answer
package demo09; import java.util.function.Consumer; public class Lambda { private static void printInfo(String[] arr, Consumer<String> con1, Consumer<String> con2){ for (String s : arr) { con1.andThen(con2).accept(s); } } public static void main(String[] args) { String[] array = {"Delireba,female", "Gulinaza,female", "Ma erzaha,male"}; printInfo(array,(s) -> { String name = s.split(",")[0]; System.out.println("full name: " + name); },(s) ->{ String sex = s.split(",")[1]; System.out.println("Gender: " + sex); });//Note that lambda's delayed execution method is used here. First, he executes the for statement in printInfo, and then executes the rewritten accept() method. Therefore, it is possible for lambda to write an s to represent a string, which can be recognized by the compiler } //Operation results // Name: dirieba // Gender: Female // Name: gulinaza // Gender: Female // Name: Ma erzaha // Gender: Male }
3.5 predict interface
Sometimes we need to judge the type of data to get a boolean result You can use Java util,function. Predict < T > interface
Abstract method: test
An abstract method boolean test(T t) contained in the predict interface is used to judge the scenario of conditions
package demo09; import java.util.function.Predicate; public class Lambda { private static boolean isLong(String length,Predicate<String> pre){ return pre.test(length); } public static void main(String[] args) { String cjy = "88cm"; String lxj = "99cm"; boolean flag1 = isLong(cjy,(length) ->{ if(Integer.parseInt(length.substring(0,2)) > 15){ return true; } return false; }); boolean flag2 = isLong(lxj,(length) ->{ if(Integer.parseInt(length.substring(0,2)) > 18){ return true; } return false; }); System.out.println(flag1? "cjy Very long":"cjy Very short"); System.out.println(flag2? "lxj Very long":"lxj Very short"); } }//The output results are long
Default method: and
Since it is conditional judgment, there will be three common logical relationships: and or not This method can be used when two predicate conditions are connected by "and" logic to achieve the effect of "and". Its source code is:
default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }
Example:
package demo09; import java.util.function.Predicate; public class Lambda { private static boolean isBothLong(String length, Predicate<String> pre1, Predicate<String> pre2) { return pre1.and(pre2).test(length); } public static void main(String[] args) { String cjy = "18cm"; String lxj = "88cm"; boolean flag1 = isBothLong(cjy, (length) -> { if (Integer.parseInt(length.substring(0, 2)) > 15) { return true; } return false; }, (length) -> { if (Integer.parseInt(length.substring(0, 2)) > 15) { return true; } return false; }); System.out.println(flag1 ? "cjy and lxj It's all very long" : "cjy and lxj It's all very short"); }//The result is that it's all very long }
Default method: or
Source code:
default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); }
The example is not done. The reason is the same as the former
Default method: negate
Source code
default Predicate<T> negate() { return (t) -> !test(t); }
It's just a negation, so there's no explanation
3.6 collection information filtering
subject
The information of multiple "name + gender" in the array is as follows. Please filter the qualified characters into the set ArrayList through the assembly of the predicate interface. Two conditions need to be met at the same time:
-
Gender must be female
-
The name is 4 characters
Data:
public static void main(String[] args) { String[] array = {"Delireba,female","Gulinaza,female","Ma erzaha,male"}; }
answer
package demo09; import java.util.ArrayList; import java.util.function.Predicate; public class Lambda { private static boolean isGirl(String s, Predicate<String> pre) { return pre.test(s); } public static void main(String[] args) { String[] array = {"Delireba,female", "Gulinaza,female", "Ma erzaha,male"}; ArrayList<String> arr = new ArrayList<>(); for (String s : array) { boolean flag1 = isGirl(s, (String str) -> str.split(",")[0].length() >= 4 && str.split(",")[1].equals("female")); if (flag1) arr.add(s); } System.out.println(arr); } //Operation results //[delireba, female, gulinaza, female] }
3.7 Function interface
java. util. function. The function < T, R > interface is used to get another type of data from one type of data. The former is called pre event and the latter is called post condition
Abstract method: apply
The main abstract methods in the Function interface are: R apply(T t),
Example: convert String to Integer
package demo09; import java.util.function.Function; public class Lambda { //Convert string to integer public static void change(String s, Function<String, Integer> fun) { int in = fun.apply(s); //Automatic unpacking System.out.println(in); } public static void main(String[] args) { change("123", (str) -> Integer.parseInt(str)); } }
Default method: andThen
Source code:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
It is the idea of chain programming, which saves the amount of code, but reduces the readability
For example: first convert the input String into Integer, and then multiply this Integer by 10
package demo09; import java.util.function.Function; public class Lambda { //Convert string to integer public static void method(String s, Function<String, Integer> fun1,Function<Integer, Integer> fun2) { System.out.println(fun1.andThen(fun2).apply(s));//Equivalent to fun2 apply(fun1.apply()); } public static void main(String[] args) { method("123", (str) -> Integer.parseInt(str),(Int) -> Int*10); } }
Incidentally, the method to quickly convert Integer to String is Integer + ""
3.8 exercise: splicing of custom function models
subject
Please use Function to splice Function models. Multiple Function operations to be performed in order are:
Example: String str = "Zhao Liying, 20";
- Intercept the age part of the number from String to get the String
- Converts a string to a number of type int
- Accumulate the int numbers in the previous step by 100 to get a String result
Problem solution
package demo09; import java.util.function.Function; public class Lambda { //Convert string to integer public static void method(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, String> fun3) { System.out.println(fun1.andThen(fun2).andThen(fun3).apply(s));//Equivalent to fun2 apply(fun1.apply()); } public static void main(String[] args) { method("Zhao Liying,20", (str) -> str.split(",")[1], Integer::parseInt, (num) -> (num + 100) + ""); }//Output result 120 }