1: Lambda expression
😀 The standard format of Lambda expression: it consists of three parts
- 1: some parameters
- 2: an arrow
- 3: a piece of code
Format:
(parameter list) - > {code of some rewriting methods}
explain:
- (): the parameter list of the abstract method in the interface. If there is no parameter, it will be empty; If there are parameters, write out the parameters. Multiple parameters are separated by commas
- ->: pass the parameter to the method body {}
- {}: override the method body of the abstract method of the interface
Short Lambda expression format:
- 1: (parameter list): the data type of the parameter list in parentheses can be omitted
- 2: (parameter list): if there is only one parameter in parentheses, the type and () can be omitted
- 3: {code}: if there is only one line of code in {}, you can omit {}, return and semicolon whether there is a return value or not
- Note: if you want to omit {}, return and semicolon, you must omit them together, otherwise you can't omit them
🤠Just talk but not practice the code on the fake style
Creating threads using Lambda expressions
Previously, we used anonymous inner classes to create threads. This is the case~
Use Lambda expressions instead of anonymous inner class implementations to create multithreads
It can also be abbreviated
Optimization of Lambda expression:
😀 1. Method reference
Define a functional interface for printing
//Define a functional interface for printing @FunctionalInterface interface Printable{ //Abstract method of printing string public abstract void print(String s); }
Main method
public class Demo1Print { /*Method parameters are passed to the Printable interface to print the string * */ public static void printString(Printable p) { p.print("I Love Java"); } public static void main(String[] args) { printString(s->System.out.println(s)); /*analysis; The purpose of Lambda expression is to print the string passed by the parameter * Passed s to system Out object, call the method pritnln() in out to output the string * be careful: * At this time, the system The out object exists, and so does the println() method * We can use method references to optimize Lambda expressions, using system The out object calls the println() method directly * Format: Object:: method * The double colon is a reference operator, and the expression in which it is located is called a method reference * */ printString(System.out::println); } }
😀 2. Reference member method by object name
Usage premise: only when the object name and member method already exist can the object name be used to reference the member method
Note: if the methods in the class are static, you cannot use object calls to directly reference static member methods with class names
practice
public class Demo2_ObjectMethodReference { public static void printString(Printable p) { p.print("java"); } public static void main(String[] args) { //Call the printString method. The parameter Printable of the method is a functional interface, so Lambda expressions can be passed printString((s)->{ //Create MethodFer object MethodFer mf = new MethodFer(); //Use the object created by MethodFer to call the method printUpperCase in this class mf.printUpperCase(s); //Output JAVA }); //Method reference (optimization) MethodFer mf2 = new MethodFer(); printString(mf2::printUpperCase); //Output JAVA //perhaps printString(new MethodFer()::printUpperCase); //Output JAVA /* * printString(MethodFer::printUpperCase); * Cannot make a static reference to the non-static method * printUpperCase(String) from the type MethodFer */ //Reference static member methods through classes printString(MethodFer::printLowerCase); //Output java } } class MethodFer{ public void printUpperCase(String str) { System.out.println(str.toUpperCase()); } public static void printLowerCase(String str) { System.out.println(str.toLowerCase()); } }
😀 3. Reference static member methods by class name
For example, the abs method in Math class is a static method
Premise:
If the class already exists and the static member method also exists, you can directly reference the static member method through the type
test
public class Demo3_StaticMethodReference { public static int calcator(int num,Calc c) { return c.calcABS(num); } public static void main(String[] args) { int num = calcator(-10,n->Math.abs(n)); System.out.println(num); /*Use method references to optimize Lambda expressions * Math Classes exist, so do abs methods * */ int num2 = calcator(-20,Math::abs); System.out.println(num2); } } @FunctionalInterface interface Calc{ public abstract int calcABS(int num); }
😀 4. Reference the member method of the parent class through super, and the member method of this class through this
public class Demo4_Super_this_MethodReference { public static void main(String[] args) { Man man = new Man(); man.show1(); man.show2(); } } //Define a parent class class Human{ //Define the sayHello method public void Say() { System.out.println("Say Hello! I am Father"); } } //Define a subclass class Man extends Human{ //Override the parent sayHello method public void Say() { System.out.println("Say Hi! I am son"); } //Define a method parameter to pass to the Greetable interface public void method(Greetable g) { g.greet(); } // public void show1() { //Call the method method. The parameter Greetable of the method is a functional interface, so you can pass a Lambda expression // method(()->{ // //Create parent object // Human h = new Human(); // //Call the sayHello method of the parent class // h.Say(); // }); //Because there is a child parent relationship, the keyword super exists to represent the parent class. You can directly use super to call the methods of the parent class // method(()->{ // super.Say(); // }); /*Continue to optimize, since you can directly use super to call the methods of the parent class * Then you can use super to reference the member methods of the class * Because super already exists, the Say method already exists * Therefore, you can directly use super to reference the Say method of the parent class */ method(super::Say); } public void show2() { //Call the method method. The parameter Greetable of the method is a functional interface, so you can pass a Lambda expression // method(()->{ // //Create this class object // Man man = new Man(); // //Call the member method of this class through this class object // man.Say(); // }); //The keyword this represents this class. You can directly use this to call the methods of this class // method(()->{ // this.Say(); // }); //Continue to optimize the use of this to reference this class method method(this::Say); } } //Define a functional interface to meet @FunctionalInterface interface Greetable{ public abstract void greet(); }
😀 5. Reference member methods through constructors
public class Demo5_ConstructorMethodReference { //Define a method parameter to pass the name and create interface public static Person getName(String n,Create c) { return c.create(n); } public static void main(String[] args) { //Call the getName method // Person name = getName("Chef xiaofugui", (s) - >{ // return new Person(s); // }); // System.out.println(name); /*Optimizing Lambda expressions using method references * Construction method new Person(String name); Known * Create object new * You can use the Person reference new to create an object * */ Person name = getName("Pikachu ",Person::new); System.out.println(name); } } //Define a functional interface @FunctionalInterface interface Create{ //The return value of the method is Person because you want to return the created object public abstract Person create(String name); } //Define a class class Person{ private String name; public Person(String name) { super(); this.name = name; } public Person() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [name=" + name + "]"; } }
😀 6. Constructor reference of array
public class Demo6_ArrayMethodReference { //Defines a method parameter that returns an array, passing the length of the array and the interface public static int[] getArr(int len,CreateArr c) { return c.create(len); } public static void main(String[] args) { //Call the getArr method int[] arr1 = getArr(10,L->new int[L]); System.out.println(Arrays.toString(arr1)); System.out.println(arr1.length); /*Optimizing Lambda expressions using method references * Known array type and array creation method * int[]Reference new to create an array according to the length passed by the parameter * */ int[] arr2 = getArr(20,int[]::new); System.out.println(Arrays.toString(arr2)); System.out.println(arr2.length); } } //Define a functional interface @FunctionalInterface interface CreateArr{ //Define an abstract method to create an array of type int. the return value is int [] public abstract int[] create(int len); }
2: Chain programming
Thought:
It is to link multiple operations (multiple lines of code) through dots to form a sentence of code, which makes the code readable. A (1) b(2). c(3)
The following functional programming is in this style
list. stream(). Filter (STR - > str.startswith ("Li")) forEach(str->System.out.println(str));
3: Common functional interfaces
Definition: an interface with only one abstract method is called a functional interface
Of course, the interface can contain other methods (default, static, private)
Use of functional interfaces:
Generally, it can be used as the parameter and return value type of a method
An instance of a functional interface as a parameter to a method
java. The lang. runnable interface is a functional interface
- Assuming that a startThread method uses this interface as a parameter, you can use a Lambda expression to pass parameters
- In fact, this situation is not fundamentally different from the construction method parameter of Thread class, which is Runnable
public class RunnableDemo { //Define a method. The parameters of startThread method use the functional interface Runnable public static void startThread(Runnable run) { //Turn on Multithreading new Thread(run) {}.start(); } public static void main(String[] args) { //Call the startThread method. The parameter of the method is an interface. Then we can pass the anonymous inner class (or implementation class) of the interface startThread(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+" --> "+"Thread on"); } }); //Call the startThread method. The parameter of the method is a functional interface, and the parameter is passed by Lambda expression startThread( ()->{ System.out.println(Thread.currentThread().getName()+" --> "+"Thread on"); }); //The optimized version of Lambda expression omits {} and; startThread( ()->System.out.println(Thread.currentThread().getName()+" --> "+"Thread on")); } }
A functional interface is used as an instance of the return value type
- When 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
public class ComparatorDemo { //Define a method whose return value type uses the functional interface Comparator public static Comparator<String> getComparator1(){ //If the return value type of the method is an interface, we can return the anonymous inner class of this interface return new Comparator<String>() { @Override public int compare(String o1, String o2) { //Sort in descending order of strings return o2.length()-o1.length(); } }; } //Improved version The return value type of the method is a functional interface, so we can return a Lambda expression public static Comparator<String> getComparator2(){ return (String o1,String o2)->{ //Use descending sorting of strings return o2.length()-o1.length(); }; } //Lambda expression optimized version public static Comparator<String> getComparator3(){ return (o1, o2)-> o2.length()-o1.length(); } public static void main(String[] args) { //Create an array of strings String[] arr = {"aaa","ccccc","bbbb"}; //Before sorting System.out.println("Array before sorting:"); System.out.println(Arrays.toString(arr)); //Sort in ascending order Arrays.sort(arr); System.out.println("Array sorted in ascending order by default:"); System.out.println(Arrays.toString(arr)); //Sort in descending order Arrays.sort(arr,getComparator3()); System.out.println("Array sorted in descending order:"); System.out.println(Arrays.toString(arr)); } }
Operation results
This package contains all functional interfaces
There are many interfaces under the package, mainly these four interfaces
1,java. util. function. Function < T, R > interface
Get another type of data from one type of data. The former is the precondition and the latter is the postcondition
The main abstract methods in the Function interface are:
R apply(T t), obtain the result of type R according to the parameters of type T, andThen(): used for combination operation
Topic: converting String to Integer
method:
/*The method parameter passes an integer of string type and a Function interface. The generic type uses < string, integer > * Use the method apply in the Function interface to convert an Integer of string type into an Integer of Integer type * */ public static void method(String str,Function<String,Integer> fun) { int num = fun.apply(str); num+=100; System.out.println(num+0); }
main:
// Output 234 method("123",new Function<String,Integer>(){ @Override public Integer apply(String t) { return Integer.parseInt(t); } }); //Simplify with Lambda expressions method("234",str-> Integer.parseInt(str));
Title: Convert "123" of String type to Integer type, add 10, and then convert to String, and use andThen
method:
public static void method(String str,Function<String,Integer> fun1,Function<Integer,String> fun2) { /* There are two steps int num = fun1.apply(str); str = fun2.apply(num); System.out.println(str); */ //Use andThen to synthesize one step String app = fun1.andThen(fun2).apply(str); System.out.println(app+0); }
main:
method("123",str->Integer.parseInt(str)+10,num->num.toString());
2,java.util.function.Supplier interface
Contains only one parameterless method
- T get() is used to obtain object data of the type specified by a generic parameter
- The Supplier interface is called the production interface (Supplier interface)
- Specify the type of the generic type of the interface, and the get method in the interface will produce what type of data
practice
public class SupplierDemo1 { //Define a method, pass the parameters of the method to the supplier < T > interface, generically execute a String, and the get method will return a String public static String getString(Supplier<String> sup) { return sup.get(); } public static void main(String[] args) { System.out.println(getString( ()->{ return "Bald head strength";})); System.out.println(getString( ()-> "Genius power")); } }
Title: find the maximum value of array elements:
Using the Supplier interface as the method parameter type, find the maximum value of the int array through the Lambda expression
public class SupplierDemo_GetArrMax { public static int getMax(Supplier<Integer> sup) { return sup.get(); } public static void main(String[] args) { //Define an integer array int[] arr = {1,8,5,9,2,55,11,77,66}; //Call the getMax method and use the Supplier interface as the method parameter type //Find the maximum value of int array through Lambda expression int maxNum = getMax( ()->{ //Define a variable to store the first number in the array int num = arr[0]; //Circular search for (int i : arr) { if(i>num) num = i; } return num; }); System.out.println("The maximum value in the array is:"+maxNum); } }
3,java. util. function. Predict interface
Function: judge the data of a certain data type, and the result returns a boolean value
The predict interface contains an abstract method:
Boolean test (T): a method used to judge the data of a specified data type
- result:
- Qualified: return true
- Unqualified: return false
practice
public class PredicateDemo { /* * Define a method * Parameter passes a String of type String * Pass a Predicate interface, and the generic type uses String * Use the test method in predict to judge the string and return the judgment result * */ public static boolean method(String str,Predicate<String> pre) { return pre.test(str); } public static void main(String[] args) { //Returns true if the string length is greater than five System.out.println(method("absafjsdf",(str)->{ return str.length()>5;})); System.out.println(method("abc",str-> str.length()>5 )); } }
Other method tests
public class PredicateDemo { //and instance All conditions must be met, equivalent to&& public static boolean checkingAnd(String str,Predicate<String> p1,Predicate<String> p2) { // return p1.test(str) && p2.test(str); return p1.and(p2).test(str); } //If an or instance condition is satisfied, it is equivalent to|| public static boolean checkingOr(String str,Predicate<String> p1,Predicate<String> p2) { // return p1.test(str) || p2.test(str); return p1.or(p2).test(str); } //negate means negative! public static boolean checkingNegate(String str,Predicate<String> p1) { // return !p1.test(str); return p1.negate().test(str); } public static void main(String[] args) { //And instance true System.out.println(checkingAnd("ABFDFD",str->str.length()>5 , str->str.contains("A"))); //Or instance true System.out.println(checkingOr("ABFDFD",str->str.length()>10 , str->str.contains("A"))); //Negate instance false System.out.println(checkingNegate("adadad",str->str.length()>5)); } }
4,java.util.function.Consumer interface
Just contrary to the Supplier interface, it does not produce a data, but consumes a data, and its data type is determined by generics
- The Consumer interface contains the abstract method void accept (T), which means to consume data of a specified generic type
- The Consumer interface is a Consumer interface. You can use the accpet method to consume data of any type specified by the generic type
- As for how to consume (use), we need to customize (output, calculation...)
practice
public class ConsumerDemo { /*Define a method Method passes the name of a string * The parameters of the method are passed to the Consumer interface, and the generic type uses String * You can use the Consumer interface to consume the name of the string * */ public static void consumerName(String name,Consumer<String> con) { con.accept(name); } public static void main(String[] args) { //Use anonymous inner classes consumerName("Bald head strength",new Consumer<String>() { public void accept(String t) { System.out.println(t); } }); //Because this interface is functional, you can use Lambda expressions // (String t )->{ System.out.println(t); } consumerName("Genius power", t->System.out.println(t)); //Realize string inversion output consumerName("Cuihua",t-> System.out.println(new StringBuffer(t).reverse()) ); } }
The default method of the Consumer interface is addThen
Function: two Consumer interfaces are required. The two Consumer interfaces can be combined to consume data
For example:
Consumer con1
Consumer con2
String s = "Hello";
con1.accpet(s);
con2.accpet(s);
- Improvement: connect two Consumer interfaces before consumption
- con1.addThen(con2).accpet(s); Who writes first, who consumes first
public class ConsumerDemo { //Define a method. The parameters of the method pass a string and two Consumer interfaces. The interface generic uses the string type public static void method(String str,Consumer<String> con1,Consumer<String> con2) { con1.accept(str); con2.accept(str); } public static void method2(String str,Consumer<String> con1,Consumer<String> con2) { con1.andThen(con2).accept(str); } public static void main(String[] args) { //Call the method method to pass a string and two Lambda expressions method("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase())); method2("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase())); } }
Title: there are multiple pieces of information in the string array, according to the format: "Name: xx. Gender: xx." Print
Use two Consumer interfaces and finally andThen
public static void print(String[] a,Consumer<String> c1,Consumer<String> c2) { for (String str : a) { c1.andThen(c2).accept(str); } } public static void main(String[] args) { //Define an array of strings String[] arr = {"Delireba,female","Gulinaza,female","Ma erzaha,male"}; print(arr,(str)->{ System.out.print("full name:"+str.split(",")[0]+". "); },(str)->{ System.out.print("Gender:"+str.split(",")[1]+". \n"); }); } }
Execution results:
4: Stream flow calculation
java.util.stream.Stream is the most commonly used interface newly added to java 1.8. (this is not a functional interface, which contains more than one abstract method)
How to get a stream:
All Collection collections can obtain streams through the default method of stream
The static method of the Stream interface can obtain the Stream corresponding to variable length parameters (the bottom layer is array)
Parameter is a variable parameter, so we can pass an array
practice
public class StreamDemo { public static void main(String[] args) { //Convert collection to stream List<String> arrayList = new ArrayList<String>(); Stream<String> stream1 = arrayList.stream(); Set<String> hashset = new HashSet<>(); Stream<String> stream2 = hashset.stream(); //If it is a Map set (double column set) Map<String,String> hashMap = new HashMap<String,String>(); //Get the key, store it in a set set, and then convert it into a stream Set<String> keySet = hashMap.keySet(); Stream<String> stream3 = keySet.stream(); //Get the value, store it in a Collection, and then convert it into a stream Collection<String> values = hashMap.values(); Stream<String> stream4 = values.stream(); //Get key value pair (key value mapping entrySet) Set<Entry<String, String>> entrySet = hashMap.entrySet(); Stream<Entry<String, String>> stream5 = entrySet.stream(); //Convert an array to a Stream stream Stream<Integer> stream6 = Stream.of(1,2,3,4,5); //Variable length parameter transitive array int[] arr1 = {666,7,888}; Stream<int[]> stream7 = Stream.of(arr1); Integer[] arr2 = {666,7,888}; Stream<Integer> stream8 = Stream.of(arr2); String[] arr3 = {"a","bb","ccc"}; Stream<String> stream9 = Stream.of(arr3); } }
Common methods in Stream forEach
- void forEach( Consumer <? super T> action);
- This method receives a Consumer interface function and gives each stream element to this function for processing
- The Consumer interface is a Consumer functional interface that can pass Lambda expressions for consumption
- Abstract methods in Consumer
- void accept(T t);
- forEach: that is, the data in the traversal stream is a termination method. After traversal, other methods in the stream stream cannot be called
public static void method1() { //Create a Stream stream Stream<Integer> stream1 = Stream.of(1,6,4,2,8); //Use the method forEach in the Stream stream to traverse the data in the Stream stream1.forEach( str->System.out.println(str)); }
Common method in Stream filter: used to filter the data in Stream
- Stream filter( Predicate<? super T> pre);
- The parameter of the filter method is a functional interface, so you can pass Lambda expressions to filter data
- Abstract methods in Predicate
- boolean test(T t);
public static void method2() { //Create a stream Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6); //The data in the convection is filtered as long as it is even Stream<Integer> stream3 = stream2.filter(num->num%2==0); //Traverse the new stream stream3.forEach(num->System.out.println(num)); }
If you need to map the data in a stream to another stream, you can use the map method
- Stream map(Function<? super T, ? extends R> mapper);
- This interface requires a Function type interface parameter, which can convert T-type data in the current stream into another R-type data
- Abstract methods in Function
- R apply(T t);
public static void method3() { //Create a stream Stream<String> stream1 = Stream.of("1","2","3","4","5"); //Converts a string to an integer type Stream<Integer> stream2 = stream1.map(str->Integer.parseInt(str)); stream2.forEach(num->System.out.println(num)); }
Common method in Stream: Count: used to count the number of elements in the Stream
- Is a termination method, and the return value is an integer of type long. Therefore, other methods cannot be called after this
public static void method4() { //Create a stream Stream<String> stream1 = Stream.of("1","2","3","4","5"); long count = stream1.count(); System.out.println(count); }
Common method in Stream: limit: used to intercept the elements in the Stream. Only the first n elements are taken
- Stream limit(long maxSize):
- The parameter is a long type. If the current length of the collection is greater than the parameter, it will be intercepted; otherwise, no operation will be performed
- The limit method is a delay method. It intercepts the stream and returns a new stream. You can continue to call other methods in the stream
public static void method5() { //Create a stream Stream<String> stream1 = Stream.of("spark","Water blue basket","Meow meow","Shaolin quack","Evil Xuanwu"); //Intercept the elements in the convection Stream<String> stream2 = stream1.limit(3); //Traverse the intercepted stream stream2.forEach(str->System.out.println(str)); }
Common methods in Stream flow: skip: used to skip elements
- Stream skip(long n);
- If the current length of the stream is greater than N, skip the first n, otherwise you will get a stream with a length of 0
public static void method6() { //Create a stream Stream<String> stream1 = Stream.of("spark","Water blue basket","Meow meow","Shaolin quack","Evil Xuanwu"); //Stream skip interception Stream<String> stream2 = stream1.skip(3); //Traverse the intercepted stream stream2.forEach(str->System.out.println(str)); }
Common method in Stream: concat: used to combine streams together
- static Stream concat(Stream <? extends T> a , Stream<? extends T> b)
public static void method7() { //Create a stream Stream<String> stream1 = Stream.of("spark","Water blue basket","Meow meow","Shaolin quack","Evil Xuanwu"); //Create another stream Stream<String> stream2 = Stream.of("1","2","3","4","5"); //Merge two flows Stream<String> stream3 = Stream.concat(stream1, stream2); //Traverse the merged stream stream3.forEach(str->System.out.println(str)); }
Execution results:
Title: filter and traverse the elements in the array using stream flow
public class Stream_List_demo { public static void main(String[] args) { //Create a new collection of storage elements ArrayList<String> list = new ArrayList<>(); list.add("Li Bai"); list.add("Li Hei"); list.add("White black"); list.add("black and white"); list.add("Li black and white"); /*Common method filtering and traversal ArrayList<String> list2 = new ArrayList<>(); for(String s:list) { if(s.startsWith("Lee ") & & S. length () = = 2){ list2.add(s); } } for (String str : list2) { System.out.println(str); } */ //Using stream filter traversal combined with functional programming list.stream().filter(str->str.startsWith("Lee")) .filter(str->str.length()==2) .forEach(str->System.out.println(str)); } }
Characteristics of Stream flow:
- It belongs to pipeline flow and can only be consumed (used) once
- After the first Stream is used up, the data will be transferred to the next Stream
- At this point, the first stream will be automatically closed and can no longer be used