Java functional design
Implementation method:
- @ FunctionalInterface interface
- Lambda syntax
- Method references
- Interface default method implementation
Lambda expressions
Lambda expressions are shorthand for anonymous inner classes, similar to syntactic sugar for anonymous inner classes; But it’s different from anonymous inner classes (more on that later).
Anonymous inner class features:
- Polymorphic based (mostly interface based programming)
- The implementation class does not need a name
- Multiple abstract methods are allowed
Lambda’s syntax is concise and unfettered by the complexities of object orientation. Features:
- To use Lambda, you must have an interface with one and only one abstract method in the interface. Lambda can only be used if the abstract methods in the interface exist and are unique, but the default interface methods and the exposed methods in declarations that override Object are excluded.
- Lambda must be used with context inference. That is, the parameter or local variable type of a method must be the interface type corresponding to Lambda in order to use Lambda as an instance of that interface.
Note: An interface with only one abstract method is called a functional interface.
The standard format consists of three parts:
- Some of the parameters
- An arrow
- A code format:
(Parameter list) ->{code for some important methods}; (): the parameter list of the abstract method in the interface, empty if there are no parameters; Write arguments if you have them, and separate multiple arguments with commas. -> : Pass: passes parameters to the method body {} {}: overrides the abstract method body of the interfaceCopy the code
The left side of the arrow operator corresponds to the list of arguments in the interface (the argument list of a lambda expression), and the right side of the arrow is the implementation of the abstract method (what a lambda expression needs to do).
Lambda optimization: omit anything that can be deduced from the context:
(argument list) : The data type of the argument list in parentheses, which can be omitted. (Argument list) : If there is only one argument in parentheses, both the type and () can be omitted. {some code} : If the code in {} is only one line, the ({}, return, semicolon) can be omitted.Copy the code
Note: to omit {},return, the semicolon must be omitted together
public class MyLambda {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run(a) {
System.out.println(Thread.currentThread().getName()+"New thread created");
}
}).start();
/ / using the Lambda
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"New thread created");
}).start();
Lambda / / optimization
new Thread(()->System.out.println(Thread.currentThread().getName()+"New thread created")).start(); }}Copy the code
1.1 No Parameter, no return
()->System.out.println("hello lambda")
Cook:
public interface Cook {
public abstract void makeFood(a);
}
Copy the code
Demo01Cook:
public class Demo01Cook {
public static void main(String[] args) {
invokeCook(new Cook() {
public void makeFood(a) {
System.out.println("Cooking..."); }});/ / using the Lambda
invokeCook(()->{
System.out.println("Cooking...");
});
Lambda / / optimization
invokeCook(()-> System.out.println("Cooking..."));
}
public static void invokeCook(Cook cook){ cook.makeFood(); }}Copy the code
1.2 No return is returned if there are parameters
x->System.out.println("hello lambda")
import java.util.function.Consumer;
/** * Created by hongcaixia on 2019/10/31. */
public class Demo2 {
public static void main(String[] args) {
Consumer<String> consumer = x-> System.out.println(x);
consumer.accept("No return with parameters"); }}Copy the code
1.3 If there are parameters, there is a return
(Person p1,Person p2)->{ return p1.getAge()-p2.getAge(); }
package com.hcx.lambda;
import java.util.Arrays;
import java.util.Comparator;
/** * Created by hongcaixia on 2019/10/26. */
public class MyArrays {
public static void main(String[] args) {
Person[] arr = {new Person(Eason Chan.40),
new Person("Chung Hon-leung".39),
new Person(Miriam Yeung.38)};
// Sort by age
Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
returno1.getAge()-o2.getAge(); }});/ / using the lambda
Arrays.sort(arr,(Person p1,Person p2)->{
return p1.getAge()-p2.getAge();
});
Lambda / / optimization
Arrays.sort(arr,(p1,p2)->p1.getAge()-p2.getAge());
Arrays.sort(arr,Comparator.comparing(Person::getAge));
for(Person p:arr){ System.out.println(p); }}}Copy the code
2. Functional interfaces
2.1 concept
Functional interface: An interface with and only one abstract method.
Functional interfaces, that is, interfaces suitable for functional programming scenarios. And functional programming in Java is Lambda, so functional interfaces are interfaces that can be applied to Lambda. Lambdas in Java can only be derived smoothly by ensuring that there is one and only one abstract method in the interface.
2.2 format
The modifierinterfaceThe name of the interface{
public abstractReturn value type Method name (optional parameter information);// Other non-abstract method content
}
Copy the code
Public abstract of abstract methods can be omitted:
public interface MyFunctionalInterface {
void myMethod(a);
}
Copy the code
2.3 @ FunctionalInterface annotation
Similar to the @Override annotation, a new annotation was introduced in Java 8 specifically for functional interfaces: @FunctionalInterface. Informational annotation types for functional interface type declarations, instances of which are created by Lambda expressions, method references, or constructor references. A FunctionalInterface can have only one abstract method, excluding the interface’s default methods and the declared public methods that override Object:
Source code comments: This annotation is the basis for defining a lambda expression, whether or not a functional interface can be annotated. Functional interfaces must have a precise abstract method, but exclude the following two: ①java8’s default, they are not abstract methods. (2) If the interface declares an abstract method that overrides a method of any object, this method is excluded.
@FunctionalInterface
public interface MyFunctionInterface {
// The only abstract method
void method(a);
// Exclude the default modifier
default void method1(a){}// exclude methods under Ojbect
int hashCode(a);
}
Copy the code
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod(a);
}
Copy the code
Note: @funcationLInterface cannot be annotated on annotations, classes, or enumerations. Once the annotation is used to define the interface, the compiler forces a check to see if the interface does have one and only one abstract method, or an error will be reported. Note that even if this annotation is not used, this is still a functional interface and works the same as long as it satisfies the definition of a functional interface.
MyFunctionalInterface:
@FunctionalInterface
public interface MyFunctionalInterface {
// Define an abstract method
public abstract void method(a);
}
Copy the code
MyFunctionalInterfaceImpl:
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
@Override
public void method(a) {}}Copy the code
Demo:
/* Use of functional interfaces: generally used as method parameters and return value types */
public class Demo {
// Define a method using the functional interface MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
// Call the show method, whose argument is an interface, so you can pass an implementation-class object for that interface
show(new MyFunctionalInterfaceImpl());
// Call the show method, whose argument is an interface, so we can pass the anonymous inner class of the interface
show(new MyFunctionalInterface() {
@Override
public void method(a) {
System.out.println("Overriding abstract methods in interfaces using anonymous inner classes"); }});// Call the show method, whose argument is a functional interface, so we can Lambda expressions
show(()->{
System.out.println("Override abstract methods in interfaces using Lambda expressions");
});
// Simplify Lambda expressions
show(()-> System.out.println("Override abstract methods in interfaces using Lambda expressions")); }}Copy the code
Case study: Analysis: The difference between functional interfaces and ordinary methods
import java.util.function.Supplier;
/** * Created by hongcaixia on 2019/11/3. */
public class MyTest {
public static void main(String[] args) {
print1("hello,world");
print2(()->"hello world");
}
public static void print1(String message){
System.out.println(message);
}
public static void print2(Supplier<String> message){ System.out.println(message.get()); }}Copy the code
The above code yields the same result, but using a functional interface is equivalent to lazily loading the data. With a functional interface, the data is not fully determined until it is actually called, similar to the push model.
Demo01Logger:
public class Demo01Logger {
// Define a method to display log information based on the log level
public static void showLog(int level, String message){
// Determine the log level. If the log level is 1, output the log information
if(level==1){ System.out.println(message); }}public static void main(String[] args) {
// Define three log messages
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
// Call the showLog method to pass the log level and log information
showLog(2,msg1+msg2+msg3); }}Copy the code
Demo02Lambda:
/* Use Lambda optimizationlog case Lambda features: Lazy loading of Lambda to use the prerequisite, there must be a functional interface */
public class Demo02Lambda {
// Define a method to display the log, with parameters passing the log level and the MessageBuilder interface
public static void showLog(int level, MessageBuilder mb){
// Determine the level of the log. If it is level 1, call the builderMessage method in the MessageBuilder interface
if(level==1){ System.out.println(mb.builderMessage()); }}public static void main(String[] args) {
// Define three log messages
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
// Call the showLog method with the MessageBuilder argument, which is a functional interface, so you can pass Lambda expressions
/*showLog(2,()->{// return msg1+msg2+msg3; }); * /
showLog(1,()->{
System.out.println("No execution until conditions are met.");
// Returns a concatenated string
returnmsg1+msg2+msg3; }); }}Copy the code
MessageBuilder:
@FunctionalInterface
public interface MessageBuilder {
// Define an abstract method for concatenating messages that returns the concatenated messages
public abstract String builderMessage(a);
}
Copy the code
Analysis: Lambda expression is used as the parameter to pass, just pass the parameter to the showLog method, only meet the conditions, log level is 1 will call the method of builderMessage interface MessageBuilder, will be string splicetogether; If the conditions are not met and the log level is not level 1, then the method builderMessage in the MessageBuilder interface is not executed, so the code for concatenating strings is not executed, so there is no wasted performance
2.4 Use functional interfaces as method parameters
Demo01Runnable:
public class Demo01Runnable {
// Define a method, startThread, whose arguments use the functional interface Runnable
public static void startThread(Runnable run){
// Enable multithreading
new Thread(run).start();
}
public static void main(String[] args) {
// Call the startThread method, whose argument is an interface, so we can pass the anonymous inner class of that interface
startThread(new Runnable() {
@Override
public void run(a) {
System.out.println(Thread.currentThread().getName()+"-- >"+"Thread started"); }});// Call the startThread method, whose argument is a functional interface, so you can pass Lambda expressions
startThread(()->{
System.out.println(Thread.currentThread().getName()+"-- >"+"Thread started");
});
// Optimize Lambda expressions
startThread(()->System.out.println(Thread.currentThread().getName()+"-- >"+"Thread started")); }}Copy the code
2.5 Use a functional interface as the return value of a method
Demo02Comparator:
import java.util.Arrays;
import java.util.Comparator;
/* If the return type of a method is a functional interface, then a Lambda expression can be returned directly. This method is invoked when a method is needed to get an object of type java.util.Comparator interface as a collator. * /
public class Demo02Comparator {
// Define a method whose return value type uses a functional interface Comparator
public static Comparator<String> getComparator(a){
The return type of the method is an interface, so we can return the anonymous inner class of that interface
/*return new Comparator
() { @Override public int compare(String o1, Return O2.length ()-o1.length(); }}; * /
// The return type of the method is a functional interface, so we can return a Lambda expression
/*return (String o1, String o2)->{return o2.length()-o1.length(); }; * /
// Continue to optimize Lambda expressions
return (o1, o2)->o2.length()-o1.length();
}
public static void main(String[] args) {
// Create an array of strings
String[] arr = {"a"."bb"."ccc"."dddd"};
// Outputs the sorted array
System.out.println(Arrays.toString(arr));
// Call the sort method of Arrays to sort the string Arrays
Arrays.sort(arr,getComparator());
// Outputs the sorted arraySystem.out.println(Arrays.toString(arr)); }}Copy the code
Each time you declare an interface, write an abstract method, and then use that interface as an argument to implement lambda… Don’t need it! This new feature is designed to keep things simple, so Java already has a bunch of functional interfaces built in.
Let’s start with an overview of some commonly used tables:
Functional interface | The parameter types | The return type | use |
---|---|---|---|
: Supplier GongGeiXing | There is no | T | Return an object of type T, T get() |
Consumer consumption | T | void | Void accept(T T); void accept(T T); |
Predicate to break stereotypes | T | boolean | Determine whether an object of type T satisfies a constraint, return a Boolean, method: Boolean test(T T) |
The Function type < T, R > Function | T | R | Apply an operation on an object of type T and return an object of type R using R apply(T, T). |
2.6 Common Functional Interfaces
(1) Supplier interface
Features: not only leave, in a method/structure parameters, the return value of Java. Util. Function. : Supplier interface contains only a no arguments method: T get (). Gets object data of the type specified by a generic parameter.
The Supplier interface is called a production interface. What type of data will be produced by the get method in the interface, given the generic type of the interface
import java.util.function.Supplier;
/** * Created by hongcaixia on 2019/10/29. */
public class MySupplier {
public static String getString(Supplier<String> supplier){
return supplier.get();
}
public static void main(String[] args) {
getString(new Supplier<String>() {
@Override
public String get(a) {
return null; }}); String s = getString(()->"Eason"); System.out.println(s); }}Copy the code
GetMax:
import java.util.function.Supplier;
/** * Created by hongcaixia on 2019/10/29. */
public class GetMax {
public static int getMaxNum(Supplier<Integer> supplier){
return supplier.get();
}
public static void main(String[] args) {
int[] arr = {-1.0.1.2.3};
int maxValue = getMaxNum(()->{
int max = arr[0];
for(int i=0; i<arr.length; i++){if(arr[i]>max){ max = arr[i]; }}return max;
});
System.out.println("The maximum value of an array element is:"+maxValue); }}Copy the code
② Consumption type: Consumer interface
Features: not only, as a method/Java structure parameters. The util. The function. The Consumer interface is just the opposite with: Supplier interface, it is not a production data, but the consumption of a data, the data type is determined by the generic. The Consumer interface contains the abstract method void Accept (T T), which means consuming data of a specified generic type.
The Consumer interface is a Consumer interface. The accept method can be used to consume whatever type of data a generic type executes
import java.util.function.Consumer;
/** * Created by hongcaixia on 2019/10/29. */
public class MyConsumer {
public static void method(String name, Consumer<String> consumer){
consumer.accept(name);
}
public static void main(String[] args) {
method("Wow!".new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("S is."+s); }}); method("Wow!",(name)->{
String s = new StringBuffer(name).reverse().toString();
System.out.println("S is."+s); }); }}Copy the code
AndThen: The default method for the Consumer interface. The purpose of andThen is to combine two Consumer interfaces to consume data
import java.util.function.Consumer;
/** * Created by hongcaixia on 2019/10/30. */
public class AndThen {
public static void method(String s, Consumer<String> consumer1,Consumer<String> consumer2){
// consumer1.accept(s);
// consumer2.accept(s);
// Use the andThen method to connect the two Consumer interfaces to consume data
Con1 consumes data before con2 consumes data
consumer1.andThen(consumer2).accept(s);
}
public static void main(String[] args) {
method("Hello",
(t)-> System.out.println(t.toUpperCase()), // Consume: convert the string to uppercase output
(t)-> System.out.println(t.toLowerCase()));// Consume: Convert string to lowercase output
method("Hello".new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s.toUpperCase());
}},new Consumer<String>() {
@Override
public void accept(String s1) { System.out.println(s1.toUpperCase()); }}); }}Copy the code
The format is name: XX. Gender: XX.” The format of the information printing request takes the action of printing the name as the Lambda instance of the first Consumer interface and the action of printing the gender as the Lambda instance of the second Consumer interface, “stitching” the two Consumer interfaces together in sequence.
public class DemoTest {
// Define a method that takes a String array and two Consumer interfaces. Generics use String
public static void printInfo(String[] arr, Consumer<String> con1,Consumer<String> con2){
// Iterate over an array of strings
for (String message : arr) {
// Connect the two Consumer interfaces using the andThen method to consume stringscon1.andThen(con2).accept(message); }}public static void main(String[] args) {
// Define an array of type string
String[] arr = { "Eason Chan, male"."Chung Hon-leung, male".Hu Ge, male };
// Call the printInfo method, passing in an array of strings and two Lambda expressions
printInfo(arr,(message)->{
// Consume: Cut the message, get the name, output in the specified format
String name = message.split(",") [0];
System.out.print("Name:"+name);
},(message)->{
// Consumption mode: Cut the message, get the age, output according to the specified format
String age = message.split(",") [1];
System.out.println("; Age:"+age+"。"); }); }}Copy the code
③ Predicate type: Predicate interface
Features: a Boolean type judgment, as a method/Java. The structure parameters util. The function. The Predicate interface functions: data of a certain data type judgment, the result returns a Boolean value
The Predicate interface contains an abstract method: Boolean test(T T): a method used to judge data of a specified data type. Result: True if the condition is met, false if the condition is not met
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/30. */
public class MyPredicate1 {
public static boolean validateStr(String str, Predicate<String> predicate){
return predicate.test(str);
}
public static void main(String[] args) {
String str = "abcdef";
boolean b = validateStr(str,string->str.length()>5);
System.out.println(b);
boolean b1 = validateStr(str, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()>5; }}); System.out.println(b1); }}Copy the code
And method: The Predicate interface has a method called AND, which represents the and relationship, and can also be used to connect two judgments
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> this.test(t) && other.test(t);
}
Copy the code
MyPredicateAnd :
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/30. */
public class MyPredicateAnd {
public static boolean validateStr(String str, Predicate<String> pre1,Predicate<String> pre2){
// return pre1.test(str) && pre2.test(str);
return pre1.and(pre2).test(str);
}
public static void main(String[] args) {
String s = "abcdef";
boolean b = validateStr(s,str->str.length()>5,str->str.contains("a")); System.out.println(b); }}Copy the code
Or method: The Predicate interface has a method or, which represents or relations. It can also be used to connect two judgments
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
Copy the code
MyPredicateOr:
package com.hcx.lambda;
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/30. */
public class MyPredicateOr {
public static boolean validateStr(String s, Predicate<String> pre1,Predicate<String> pre2){
// return pre1.test(s) || pre2.test(s);
return pre1.or(pre2).test(s);
}
public static void main(String[] args) {
String s = "acdef";
boolean b = validateStr(s,str->str.length()>5,str->str.contains("a"));
validateStr(s, new Predicate<String>() {
@Override
public boolean test(String str) {
return s.length()>5; }},new Predicate<String>() {
@Override
public boolean test(String str) {
return s.contains("a"); }}); System.out.println(b); }}Copy the code
Negate method: The Predicate interface has a negate method, which also means negate
default Predicate<T> negate(a) {
return(t) -> ! test(t); }Copy the code
MyPredicateNegate:
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/30. */
public class MyPredicateNegate {
public static boolean validateStr(String s, Predicate<String> pre){
// return ! pre.test(s);
return pre.negate().test(s);
}
public static void main(String[] args) {
String s = "acde";
boolean b = validateStr(s,str->str.length()>5); System.out.println(b); }}Copy the code
MyTest:
package com.hcx.lambda;
import java.util.ArrayList;
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/30. */
public class MyTest {
public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2) {
ArrayList<String> list = new ArrayList<>();
for (String s : arr) {
boolean b = pre1.and(pre2).test(s);
if(b) { list.add(s); }}return list;
}
public static void main(String[] args) {
String[] array = {"Dilieba, female."."Gulinaza, female"."Tong Liya, female"."Zhao Liying, female"};
ArrayList<String> list = filter(array,
s -> s.split(",") [1].equals("Female"),
s -> s.split(",") [0].length() == 4);
for(String s : list){ System.out.println(s); }}}Copy the code
④ Conversion type: Function interface
Features: the input and output of Java. Util. The function. The function < T, R > interface is used to according to a type of data to get another type of data, the former is called precondition, the latter is called post-conditions.
The main abstract method in the Function interface is: R apply(T T), which obtains the result of type R based on the parameters of type T. The scenarios used are as follows: convert String to Integer.
package com.hcx.lambda;
import java.util.function.Function;
/** * Created by hongcaixia on 2019/10/30. */
public class MyFunction {
public static void change(String str, Function<String,Integer> function){
// Integer i = function.apply(str);
// Automatic unpacking Integer Automatically converts to int
int i = function.apply(str);
System.out.println(i);
}
public static void main(String[] args) {
String s = "1234";
change(s,str->Integer.parseInt(str));
inti = Integer.parseInt(s); System.out.println(i); }}Copy the code
AndThen method:
package com.hcx.lambda;
import java.util.function.Function;
Function
fun1 :Integer I = fun1. Apply ("123")+10; Function
fun2 :String s = fun2.apply(I); * Created by hongcaixia on 2019/10/31. */
,string>
,integer>
public class MyFunctionTest {
public static void change(String str, Function<String,Integer> fun1,Function<Integer,String> fun2){
String string = fun1.andThen(fun2).apply(str);
System.out.println(string);
}
public static void main(String[] args) {
change("123",str->Integer.parseInt(str)+10,i->i+""); }}Copy the code
Custom function model stitching Demo:
package com.hcx.lambda;
import java.util.function.Function;
/** * String = "STR,20"; * 1. Truncate the numeric age part of the string to get the string; * 2. Convert the string from the previous step to an int; * 3. Add 100 to the int number in the previous step to get the int number. * Created by hongcaixia on 2019/10/31. */
public class MyFunctionTest2 {
public static int change(String str, Function
fun1,Function
fun2, Function
fun3)
,integer>
,integer>
,string>{
return fun1.andThen(fun2).andThen(fun3).apply(str);
}
public static void main(String[] args) {
int num = change("Zhao Liying,32",str->str.split(",") [1],
str->Integer.parseInt(str),
i->i+100); System.out.println(num); }}Copy the code
Note: Using an anonymous inner class generates an extra class after compilation, whereas using a lambda, with the invokedynamic instruction at the bottom, there are no extra classes
Method reference
A method reference can be used if a method already implements something in the lambda body. Method references are a simplification of lambda
MyPrintable:
public interface MyPrintable {
void print(String str);
}
Copy the code
DemoPrint:
public class DemoPrint {
private static void printString(MyPrintable data){
data.print("Hello,World");
}
public static void main(String[] args) {
printString(s->System.out.println(s));
printString(new MyPrintable() {
@Override
public void print(String str) { System.out.println(str); }}); }}Copy the code
Improvement:
public class DemoPrint {
private static void printString(MyPrintable data){
data.print("Hello,World");
}
public static void main(String[] args) {
//printString(s->System.out.println(s));printString(System.out::println); }}Copy the code
Method references
The double colon :: is the reference operator, and the expression it is in is called a method reference. If the function scheme Lambda is expressing already exists in an implementation of a method, then the method can be referred to by a double colon as an alternative to Lambda.
Three formats:
- Object :: Instance method name
- Class :: Static method name
- Class :: Instance method name
Analysis of the
- Lambda expression:
s -> System.out.println(s);
- Method Reference writing:
System.out::println
The first way is to take the argument and pass it to the system.out.println method via Lambda. The second option: simply replace the Lambda with the println method in system.out.
Note: The argument list and return value types of the methods called in the lambda body are the same as those of the abstract methods of the functional interface. The arguments passed in a Lambda must be of the type that the method in the method reference can receive, or an exception will be thrown
3.1 Referring to member methods by object names
@Test
public void test(a){
Person person = new Person();
Supplier<String> supplier =() -> person.getName();
System.out.println(supplier.get());
Supplier<Integer> supplier1 = person::getAge;
System.out.println(supplier1.get());
}
Copy the code
MyPrintable:
public interface MyPrintable {
void print(String str);
}
Copy the code
MethodReadObj:
public class MethodReadObj {
public void printUpperCaseString(String str){ System.out.println(str.toUpperCase()); }}Copy the code
MethodReference1:
public class MethodReference1 {
public static void printString(MyPrintable p){
p.print("hello");
}
public static void main(String[] args) {
printString(str-> {
MethodReadObj methodReadObj = new MethodReadObj();
methodReadObj.printUpperCaseString(str);
});
MethodReadObj object already exists * 2. The member method printUpperCaseString already exists * so you can reference the member method */ using the object name
MethodReadObj methodReadObj = newMethodReadObj(); printString(methodReadObj::printUpperCaseString); }}Copy the code
3.2 Referring to static methods by class name
If the class already exists and the static method already exists, the static member method can be referenced directly by the class name
@Test
public void test1(a){
Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);
Comparator<Integer> comparator1 = Integer::compare;
}
Copy the code
MyCalc:
public interface MyCalc {
int calc(int num);
}
Copy the code
MethodRerference2:
public class MethodRerference2 {
public static int method(int num,MyCalc c){
return c.calc(num);
}
public static void main(String[] args) {
int number = method(-10, num -> Math.abs(num));
int number1 = method(-10, Math::abs); System.out.println(number); System.out.println(number1); }}Copy the code
Refer to instance methods by class name
@Test
public void test2(a){
BiPredicate<String,String> biPredicate = (x,y) -> x.equals(y);
BiPredicate<String,String> biPredicate1 = String::equals;
}
Copy the code
Note: In this case, certain conditions must be met: the first argument in the lambda expression is the caller in the lambda body, and the second argument is the argument in the lambda body
3.3 Referring to member methods through super
If inheritance exists, method references can also be used instead when a super call is needed in a Lambda. MyMeet :
@FunctionalInterface
public interface MyMeet {
void meet(a);
}
Copy the code
Parent:
public class Parent {
public void hello(a){
System.out.println("Hello, I 'm the Parent"); }}Copy the code
Child:
public class Child extends Parent{
@Override
public void hello(a) {
System.out.println("Hello, I 'm the Child");
}
public void method(MyMeet myMeet){
myMeet.meet();
}
public void show(a){
method(()->{
Parent parent = new Parent();
parent.hello();
});
// Call the parent class with the super keyword
method(()->super.hello());
/** * Use method references: use super to refer to a member method of the parent class: * 1. Super already exists * 2. The parent member method hello already exists * you can use super directly to refer to the parent member method */
method(super::hello);
}
public static void main(String[] args) {
newChild().show(); }}Copy the code
3.4 Referencing member methods through this
This represents the current object. If the method you want to refer to is a member method in the current class, you can use the format of this:: member method to refer to MyWallet:
@FunctionalInterface
public interface MyWallet {
void buy(a);
}
Copy the code
BuyThing:
public class BuyThing {
public void buyCar(a){
System.out.println("Don't touch me when you get one.");
}
public void getSalary(MyWallet myWallet){
myWallet.buy();
}
public void method(a){
getSalary(()->this.buyCar());
/** * 1. This already exists * 2. This member method buyCar already exists * so we can use this to refer to this member method buyCar */
getSalary(this::buyCar);
}
public static void main(String[] args) {
newBuyThing().method(); }}Copy the code
3.5 constructor references for class
Because the constructor name is exactly the same as the class name, it is not fixed. So the constructor reference is formatted with the class name ::new.
public void test3(a){
Supplier<Person> personSupplier = ()->new Person();
The constructor reference is a no-parameter constructor because the Supplier get method has no arguments
Supplier<Person> personSupplier1 = Person::new;
}
public void test4(a){
Function<Integer,Person> personFunction = (x)->new Person(x);
// Constructor reference Is a constructor for an integer because the apply method in Function has only one argument
Function<Integer,Person> personFunction1 = Person::new;
}
Copy the code
Note: The argument list of the constructor to be called is the same as the argument list of the abstract method in the functional interface
Person:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
}
Copy the code
PersonBuilder:
@FunctionalInterface
public interface PersonBuilder {
// Create a Perosn object based on the passed name
Person builderPerson(String name);
}
Copy the code
Demo:
public class Demo {
// Pass the name and PersonBuilder interface to create a Person object from the name
public static void printName(String name,PersonBuilder personBuilder){
Person person = personBuilder.builderPerson(name);
System.out.println(person.getName());
}
public static void main(String[] args) {
printName("hongcaixia",str->new Person(str));
1. Constructor new Person(String name) known * 2. You can use Person to reference new to create objects */
printName("hongcaixia",Person::new); }}Copy the code
3.6 Array constructor references
Arrays are subclasses of Object, so they also have constructors with slightly different syntax. Format: Type [] : : new
public void test5(a) {
Function<Integer, String[]> function = (x) -> new String[x];
String[] strings = function.apply(10);
Function<Integer,String[]> function1 = String[]::new;
String[] strings1 = function1.apply(10);
}
Copy the code
ArrayBuilder:
@FunctionalInterface
public interface ArrayBuilder {
// A method to create an array of type int, passing the length of the array, returns the created array of type int
int[] builderArray(int length);
}
Copy the code
DemoArrayBuilder:
public class DemoArrayBuilder {
public static int[] createArray(int length,ArrayBuilder arrayBuilder){
return arrayBuilder.builderArray(length);
}
public static void main(String[] args) {
int[] arr1 = createArray(5,length -> new int[length]);
System.out.println(arr1.length);
Int [] creates an array */ based on the length passed to it
int[] arr2 = createArray(10.int[] : :new); System.out.println(Arrays.toString(arr2)); System.out.println(arr2.length); }}Copy the code
Four, StreamAPI
Streams are data channels that manipulate sequences of elements generated by data sources (collections, arrays, and so on).
package com.hcx.stream;
import java.util.ArrayList;
import java.util.List;
/** * Created by hongcaixia on 2019/10/31. */
public class MyStream1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add(Eason Chan);
list.add("Chen Xiaochun");
list.add("Chung Hon-leung");
list.add("Chen qi");
list.add(William Chan);
// Filter the beginning of the Chen, the name is three words
List<String> chenList = new ArrayList<>();
for(String item : list){
if(item.startsWith("Chen")){
chenList.add(item);
}
}
List<String> threeList = new ArrayList<>();
for(String item : chenList){
if(item.length()==3){ threeList.add(item); }}// Traversal the output to meet the condition
for(String item : threeList){
System.out.println(item);
}
System.out.println("= = = = = = = = = = = = = = = = = = = = =");
// Use Stream
list.stream().filter(str->str.startsWith("Chen"))
.filter(str->str.length()==3) .forEach(str-> System.out.println(str)); }}Copy the code
A Stream is a queue of elements from a data source
- Elements are objects of a specific type that form a queue.
- Data source Indicates the source of the flow. It could be collections, arrays, etc.
- The Stream itself does not store elements, but evaluates them on demand.
- Stream does not change the source object and can return a new Stream holding the result
- Stream operations are deferred, meaning they wait until the result is needed
Unlike the previous Collection operation, the Stream operation has two basic characteristics:
- Pipelining: All intermediate operations return the flow object itself. These operations can be cascaded into a pipe, as in fluent style. This allows you to optimize operations, such as delay and short-circuiting.
- Internal iteration: Previously, collections were iterated explicitly outside the collection by Iterator or enhanced for. This is called external iteration. A Stream provides a way to iterate internally, and a Stream can call the traversal method directly.
The Stream operation has three steps:
- Create a Stream: A data source (such as a collection, array) that retrieves a Stream
- Intermediate operation: a chain of operations that processes data from a data source
- Termination operation: A termination operation that performs an intermediate chain of operations and produces a result
Note that a “Stream” is a functional model of collection elements. It is not a collection, nor is it a data structure, and does not store any elements (or their address values) on its own.
import java.util.*;
import java.util.function.Predicate;
/** * Created by hongcaixia on 2019/10/31. */
public class MyPredicate {
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(10.20.3, -5, -8);
Collection<Integer> positiveNum = filter(nums,num->num>0);
Collection<Integer> negativeNum = filter(nums,num->num<0);
System.out.println(positiveNum);
System.out.println(negativeNum);
}
private static <E> Collection<E> filter(Collection<E> source, Predicate<E> predicate){
List<E> list = new ArrayList<>(source);
Iterator<E> iterator = list.iterator();
while (iterator.hasNext()){
E element = iterator.next();
if(!predicate.test(element)){
iterator.remove();
}
}
returnCollections.unmodifiableList(list); }}Copy the code
4.1 access to flow
Java.util.stream. stream
is a common stream interface added to Java8. The java.util.Collection interface uses the default stream method to fetch streams, so all of its implementation classes can fetch streams.
- Stream () : Gets a serial stream
- ParallelStream () : Gets parallel streams
package com.hcx.stream;
import java.util.*;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class GetStreamFromCollection {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
Vector<String> vector = newVector<>(); Stream<String> stream3 = vector.stream(); }}Copy the code
The java.util.Map interface is not a subinterface of Collection, and its K-V data structure does not match the single feature of stream elements. Therefore, the corresponding stream needs to be divided into key, value or entry.
package com.hcx.stream;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class GetStreamFromMap {
public static void main(String[] args) {
Map<String,String> map = newHashMap<>(); Stream<Map.Entry<String, String>> stream1 = map.entrySet().stream(); Stream<String> stream2 = map.keySet().stream(); Stream<String> stream3 = map.values().stream(); }}Copy the code
If you use an array instead of a collection or a map, you cannot add a default method to an array object, so the Stream interface provides a static method of:
package com.hcx.stream;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class GetStreamFromArray {
public static void main(String[] args) {
String[] array = {Eason Chan."Chung Hon-leung".Miriam Yeung}; Stream<String> stream = Stream.of(array); }}Copy the code
④ Get infinite flow
public void test6(a) {
Stream<Integer> stream = Stream.iterate(0, x -> x + 2);
}
public void test7(a) {
Stream<Double> stream = Stream.generate(() -> Math.random());
}
Copy the code
Note: The argument to the of method is a mutable argument, so arrays are supported.
Conclusion:
- All of the
Collection
All sets can pass throughstream
The default method gets the stream; Stream
Static methods of the interfaceof
You can get the corresponding stream of the array
4.2 Common Methods of flow
Methods can be divided into two types:
- Delay methodThe return value type is still
Stream
A method of the interface’s own type, and therefore supports chained calls. (All methods except the finalizer are delay methods.) - Put an end to the methodThe return value type is no longer
Stream
Methods of the interface’s own type, so chain calls like StringBuilder are no longer supported. Finalizing methods include the count and forEach methods.
① One by one: forEach
void forEach(Consumer<? super T> action);
Copy the code
This method receives a Consumer interface function that hands each stream element to the function for processing. Consumer is a consumptive functional interface that passes lambda expressions and consumes data
package com.hcx.stream;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class StreamForEach {
public static void main(String[] args) {
Stream<String> stream = Stream.of("Zhang"."Bill"."Fifty"); stream.forEach(str-> System.out.println(str)); }}Copy the code
② Filter: Filter can be used to change a stream into another subset stream. Method signature:
Stream<T> filter(Predicate<? super T> predicate);
Copy the code
The interface accepts a Predicate function interface argument (which can be a Lambda or method reference) as a filter condition.
Java. Util. Stream. The Predicate functional interface only abstract method is: the Boolean test (T, T); This method yields a Boolean value indicating whether the specified condition is met: if the result is true, the filter method of the Stream Stream will retain the element; If the result is false, the filter method will discard the element.
public class StreamFilter {
public static void main(String[] args) {
Stream<String> stream = Stream.of(Eason Chan.William Chan."Chen qi"."Chung Hon-leung");
Stream<String> stream1 = stream.filter(str -> str.startsWith("Chen")); stream1.forEach(str-> System.out.println(str)); }}Copy the code
Note: a Stream is a piped Stream and can only be consumed once. When the Stream calls the method, the data flows back to the next Steam, and the first Stream is already used and closed, so the first Stream can no longer call the method.
③ Mapping: A map receives a lambda, converts the element to another form or extracts information, and takes as an argument a function that is applied to each element and maps it to a new element. Map elements in a stream to another stream. Method signature:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Copy the code
This interface requires a Function Function interface argument that converts type T data from the current stream to another type R stream. Java. Util. Stream. The Function, functional interface, the only method is: abstract R apply (T, T); This can convert a T type to an R type, and the action of conversion is called mapping.
public class StreamMap {
public static void main(String[] args) {
Stream<String> stream = Stream.of("1"."2"."3"); Stream<Integer> integerStream = stream.map(str -> Integer.parseInt(str)); integerStream.forEach(i-> System.out.println(i)); }}Copy the code
public void test8(a) {
Person person = new Person("hcx".24);
Person person1 = new Person("hcx2".24);
List<Person> list = new ArrayList<>();
list.add(person);
list.add(person1);
list.stream().map(Person::getName).forEach(System.out::println);
}
Copy the code
④flatMap takes a function as a parameter, replaces each value in the stream with another stream, and then joins all streams into a single stream. The simple explanation is to convert several small lists into one large list. For example: [[‘ a ‘, ‘b’], [‘ c ‘, ‘d’]] – > [‘ a ‘, ‘b’, ‘c’, ‘d’] if we use the commonly used the map () method to obtain lowercaseWords data structure as follows: [[‘ a ‘, ‘b’, ‘c’], [‘ m ‘, ‘d’, ‘w’], [‘ k ‘, ‘e’, ‘t’]]. If we want to get, such as: ‘a’, ‘b’, ‘c’, ‘m’, ‘d’, ‘w’, ‘k’, ‘e’, ‘t’] such data structure of data, you need to use flatMap () method.
public void test9(a) {
List<String> list = Arrays.asList("a"."b"."c");
Stream<Stream<Character>> streamStream = list.stream().map(MethodReference::filterCharacter);
streamStream.forEach((stream)->stream.forEach(System.out::println));
/ / use flatMap
Stream<Character> characterStream = list.stream().flatMap(MethodReference::filterCharacter);
characterStream.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
Copy the code
The reduce protocol combines elements in the stream repeatedly to get a value
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class StreamReduce {
public static void main(String[] args) {
sum(1.2.3.4.5);
}
private static void sum(Integer... nums){ Stream.of(nums).reduce(Integer::sum).ifPresent(System.out::println); }}Copy the code
@Test
public void test10(a) {
List<Integer> list = Arrays.asList(1.2.3.4.5);
Integer sum = list.stream().reduce(0,(x,y)->x+y);
System.out.println(sum);
}
Copy the code
The final method stream provides a count method to count the number of elements. This method returns a long value representing the number of elements:
package com.hcx.stream;
import java.util.ArrayList;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class StreamCount {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Stream<Integer> stream = list.stream();
longcount = stream.count(); System.out.println(count); }}Copy the code
Limit method can be used to intercept convection, only the first N. Method signature:
Stream<T> limit(long maxSize);
Copy the code
The parameter is a long. If the current length of the collection is greater than the parameter, it is truncated. Otherwise, no operation is performed to delay the method, just intercepting the elements in the Stream, returning a new Stream, and continuing to call other methods in the Stream
public class StreamLimit {
public static void main(String[] args) {
String[] str = {"1"."2"."3"."4"."5"};
Stream<String> stream = Stream.of(str);
Stream<String> limitStream = stream.limit(3); limitStream.forEach(string-> System.out.println(string)); }}Copy the code
If you want to skip the first few elements, you can use the skip method to get a new truncated stream:
Stream<T> skip(long n);
Copy the code
If the current length of the stream is greater than n, the first n are skipped; Otherwise you get an empty stream of length 0
public class StreamSkip {
public static void main(String[] args) {
String[] str = {"1"."2"."3"."4"."5"};
Stream<String> stream = Stream.of(str);
Stream<String> skipStream = stream.skip(3); skipStream.forEach(string-> System.out.println(string)); }}Copy the code
If you have two streams that you want to merge into one Stream, you can use concat, the static method of the Stream interface
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
Copy the code
Note: This is a static method, unlike the concat method in java.lang.String
public class StreamConcat {
public static void main(String[] args) {
Stream<String> stream1 = Stream.of(Eason Chan.William Chan."Chen qi"."Chung Hon-leung");
String[] arr = {"1"."2"."3"}; Stream<String> stream2 = Stream.of(arr); Stream<String> concatStream = Stream.concat(stream1, stream2); concatStream.forEach(str-> System.out.println(str)); }}Copy the code
⑩ Sorted: sorted
- Sorted () is sorted naturally
- Sorted (Comparator com) custom sort
- AllMatch checks whether all elements match
- AnyMatch checks whether at least one element matches
- NoneMatch checks to see if 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 Returns the maximum value in the stream
- Min returns the minimum value in the stream
public class StreamSort {
public static void main(String[] args) {
Integer[] nums = {2.9.0.5, -10.90}; Stream<Integer> numsStream = Stream.of(nums); Stream<Integer> sortedStram = numsStream.sorted(); sortedStram.forEach(num -> System.out.println(num)); }}Copy the code
⑪Collect transforms the stream into something else. Receives an implementation of a Collector that summarizes the elements in the stream
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** * Created by hongcaixia on 2019/10/31. */
public class StreamCollect {
public static void main(String[] args) {
List<Integer> list = Stream.of(1.2.3.4.5).collect(Collectors.toList());
List<Integer> list1 = Stream.of(1.2.3.4.5).collect(LinkedList::new,List::add,List::addAll);
System.out.println(list.getClass());//class java.util.ArrayList
System.out.println(list1.getClass());//class java.util.LinkedList}}Copy the code
@Test
public void test11(a) {
Person person = new Person("hcx".24);
Person person1 = new Person("hcx2".24);
List<Person> list = new ArrayList<>();
list.add(person);
list.add(person1);
List<String> collect = list.stream().map(Person::getName).collect(Collectors.toList());
}
Copy the code
4.3 Parallel flow and Sequential flow
A parallel stream is a stream that splits a piece of content into chunks of data and processes each chunk separately with a different thread. Parallel () and sequential() allow switching between parallel and sequential streams.
@Test
public void test12(a) {
/ / order flow
LongStream.rangeClosed(0.100).reduce(0,Long::sum);
/ / parallel flows
long reduce = LongStream.rangeClosed(0.100).parallel().reduce(0, Long::sum);
/ / 5050
System.out.println(reduce);
}
Copy the code