Chain programming
summary
JDK chain programming has the advantages of strong programmability, readability and concise code. The principle of chain programming is to return a this object, that is, to return itself to achieve the chain effect. For example, the StringBuilder of JDK is to realize the effect of chain programming.
StringBuilder builder = new StringBuilder(); builder.append("aa").append("bb").append("cc").append("dd").append("ee");
Code example
Custom implementation
Student java
package cn.itxs.chain; public class Student { private String name; private int age; private String address; public String getName() { return name; } public Student setName(String name) { this.name = name; return this; } public int getAge() { return age; } public Student setAge(int age) { this.age = age; return this; } public String getAddress() { return address; } public Student setAddress(String address) { this.address = address; return this; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", address='" + address + '\'' + '}'; } }
Test class
package cn.itxs.chain; public class ChainMain { public static void main(String[] args) { Student student = new Student(); student.setName("Li Shanshan").setAge(20).setAddress("Chaoyang District of Beijing City"); System.out.println(student.toString()); } }
Lombok use
Add dependency to pom file
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency>
User class user java
package cn.itxs.other; import com.sun.istack.internal.NotNull; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; @Accessors(chain = true) @Data @RequiredArgsConstructor(staticName = "of") public class User { @NotNull private String name; private int age; }
Test class
package cn.itxs.other; public class UMain { public static void main(String[] args) { User user = User.of("Chen Shuishui").setAge(25); System.out.println(user.toString()); } }
Lambada expression
summary
- Lambda expression is an anonymous function. We can understand lambda expression as a piece of code that can be passed; Lambada expression is a new feature of JDK8 to avoid too many anonymous inner class definitions; Get rid of a pile of meaningless code, leave only the core logic and focus on logic implementation; You can write more concise, flexible and elegant Java code.
- Lambda expression is very simple, so it must be used in a special context, so that the compiler can infer which method the lambda expression is and calculate the value of the lambda expression. The value of the lambda expression is the entry address of the method. Therefore, lambda can only implement the interface with only one abstract method.
- Functional interface refers to an interface with only one abstract method; Java 8 introduces annotation @ functional interface to modify and check functional interfaces.
- In case of multiple interface inheritance, the problem of default method coverage may occur. In this case, you can specify which interface's default method implementation is used.
- Basic grammar
- A new operator "- >", called arrow operator or Lambda operator, is introduced into Java 8; The arrow operator splits the Lambda expression into left and right parts.
- Left: parameter list of Lambda expression
- If there is only one parameter, the left parenthesis can not be written, but it is recommended to bring parentheses based on readability.
- The data type of the parameter list of Lambda expression can be omitted, because the JVM compiler infers the data type through the context, that is, "type inference" (syntax sugar); If you want to write data types, you have to write them all.
- Right: the function to be executed in the Lambda expression, that is, the Lambda body; There is only one statement on the right. Braces {} and return can be omitted. There are three forms
- No parameter, no return value
- There are parameters but no return value
- There are parameters and return values
- Method reference
- When the Lambda body has only one statement, you can reference methods and constructors through English "::.
Code example
Thread call
When Java does not support lambda expressions, we need many lines of code to create a thread. The creation of a thread can be completed with one sentence of code using lambda expressions. Runnable is a functional interface.
new Thread(() -> System.out.println("hello lambada thread demo")).start();
Custom functional interface
The JDK8 interface supports the default implementation method. There is no default method before. Modifying the interface code will have a great impact; The function interface feature can provide a default implementation
Custom functional interface: OperateInterface
package cn.itxs.lambada; @FunctionalInterface public interface OperateInterface { int caculate(int num1,int num2,int num3); default int subtract(int num1, int num2) { return num1 -num2; } }
Test class
package cn.itxs.lambada; public class LambadaMain { private static void printDemo(int num1,int num2,int num3, OperateInterface operateInterface) { System.out.println(operateInterface.caculate(num1, num2, num3)); } private static void printDescription(String description, UserBuilder userBuilder) { System.out.println(userBuilder.build(description).getDescription()); } public static void main(String[] args) { //lambda expressions implemented directly printDemo(10,20,30,(int num1,int num2,int num3) -> (num1 + num2) * num3); //Class static method lambda expression printDemo(10,20,30,(int num1,int num2,int num3) -> Operater.muti(10,20,30)); //Class static method reference printDemo(10,20,30,Operater::muti); Operater operater = new Operater(); //Object method lambda expression printDemo(10,20,30,(int num1,int num2,int num3) -> operater.muti2(10,20,30)); //Object method reference printDemo(10,20,30,operater::muti2); printDescription("Constructor reference test lambda expression",description -> new User(description)); printDescription("Constructor reference test method reference",User::new); } } class Operater { public static int muti(int num1, int num2, int num3){ return num1 * num2 * num3; } public int muti2(int num1,int num2,int num3){ return num1 * num2 - num3; } } @FunctionalInterface interface UserBuilder{ User build(String description); } class User{ private String description; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public User(String description) { this.description = description; } }
Common functional interface
summary
- JDK provides a large number of built-in functional interfaces for us to use, making the use of lambda expressions more convenient and efficient; Lambda expressions are the basis of functional programming.
- Jdk8 Java util. The function package provides common functional interfaces.
Predict interface
Predicate is an assertion function interface. It receives the parameter object T and returns a boolean result. In JDK, the function interface code is as follows:
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-y2grfqz0-1642690079887) (image-20220119164339846. PNG)]
Test class
package cn.itxs.func; import java.util.function.Predicate; public class FunctionalMain { public static void main(String[] args) { Predicate<Integer> predicate = i -> { System.out.println("Assert functional interface test, input value:" + i); return i > 100; }; System.out.println(predicate.test(100)); System.out.println(predicate.test(101)); Predicate<String> predicateStr = str -> { System.out.println("Assert functional interface test, input value:" + str); return "true".equals(str);}; System.out.println(predicateStr.test("true")); System.out.println(predicateStr.test("haha")); //Interfaces generally have encapsulation of basic types, and there is no need to specify generic types when using specific types of interfaces, such as longpredict, doublepredicte, IntConsumer, etc LongPredicate longPredicate = i -> { System.out.println("Long integer assertion, functional interface test, input value:" + i); return i > 100000; }; System.out.println(longPredicate.test(100000)); System.out.println(longPredicate.test(100001)); } }
Supplier and Consumer interfaces
- Supplier supplier function interface: it does not receive parameters and provides the creation factory of T object
- Consumer function interface: receives a T-type parameter and returns no result
@FunctionalInterface public interface Supplier<T> { T get(); } @FunctionalInterface public interface Consumer<T> { void accept(T t); }
Test code
package cn.itxs.func; import java.util.Random; import java.util.function.Consumer; import java.util.function.Supplier; public class FunctionalMain { public static void main(String[] args) { Supplier<Integer> supplier = () -> { System.out.println("Supplier functional interface test, randomly generate integer values within 100"); return new Random().nextInt(100); }; System.out.println(supplier.get()); Consumer<String> consumer = (message) -> { System.out.println("Consumer functional interface test, received message" + message); }; consumer.accept("hello java"); } }
Function and BiFunction interfaces
- The Function interface receives the parameter object T and returns the result object R.
- The BiFunction interface is just one more input than the Function interface.
@FunctionalInterface public interface Function<T, R> { R apply(T t); } @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); }
Test code
package cn.itxs.func; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiFunction; import java.util.function.Function; public class FunctionalMain { public static void main(String[] args) { Function<Integer, List<Integer>> function = (i) ->{ System.out.println("Function Functional interface test, enter an integer and return a set of 3 copied values"); List<Integer> listInt = new CopyOnWriteArrayList<>(); listInt.add(i); listInt.add(i); listInt.add(i); return listInt; }; List<Integer> list1 = function.apply(100); System.out.println(list1); BiFunction<Integer,Integer,List<String>> biFunction = (i1, i2) -> { System.out.println("BiFunction Functional interface test, enter an integer and return the string set of the sum of two numbers"); List<String> listStr = new ArrayList<>(); listStr.add(String.valueOf(i1+i2)); return listStr; }; List<String> list2 = biFunction.apply(100001,200001); System.out.println(list2); } }
UnaryOperator and BinaryOperator interfaces
- The UnaryOperator interface receives the parameter object T and returns the result object t.
- The BinaryOperator interface adds one more receiving parameter object than the UnaryOperator interface. Receive two T objects and return a T object result.
@FunctionalInterface public interface UnaryOperator<T> extends Function<T, T> { static <T> UnaryOperator<T> identity() { return t -> t; } } @FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T,T,T> { public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) <= 0 ? a : b; } public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) { Objects.requireNonNull(comparator); return (a, b) -> comparator.compare(a, b) >= 0 ? a : b; } }
Test class
package cn.itxs.func; import java.util.function.BinaryOperator; import java.util.function.UnaryOperator; public class FunctionalMain { public static void main(String[] args) { UnaryOperator<Integer> unaryOperator = (i) -> { System.out.println("unaryOperator Functional interface test, enter integer and return integer+1"); return i+1; }; System.out.println(unaryOperator.apply(100)); BinaryOperator<String> binaryOperator = (str1,str2) -> { System.out.println("binaryOperator Functional interface test, enter two strings and return two strings"); return str1 + str2; }; System.out.println(binaryOperator.apply("good deed", "In pairs")); } }
Optional
summary
Optional wrap the parameters of all methods with optional to avoid null pointers.
Basic use
package cn.itxs.optional; import java.util.Optional; public class OptionalMain { public static void main(String[] args) { // The third way is to create an empty Optional object directly through the empty method Optional<Object> option = Optional.empty(); //It is not allowed to wrap null objects, otherwise the program will report an error //Optional op = Optional.of(null); //The package object is allowed to be nul, and empty option is returned when it is null Optional op = Optional.ofNullable(null); System.out.println(op); //When using get() to get the object in the container, if the object is null, there will be Java util. NoSuchElementException exception. Therefore, it is best to judge isPresent() first. If it returns true, it indicates that it exists, and then obtain it //op.get(); //Judge whether two options are equal, mainly whether the wrapped objects are equal Optional op1 = Optional.of("java"); Optional op2 = Optional.ofNullable("java"); System.out.println(op1.equals(op2)); op2 = Optional.of("java1"); System.out.println(op1.equals(op2)); //If the value exists and meets the assertion, it returns Optional that meets the condition, otherwise it returns empty, which is often used for filtering Optional<String> op3 = Optional.of("itxiaoshen"); Optional r1 = op3.filter((str)-> str.length() > 15); System.out.println(r1); //If the value exists, perform the mapping function operation on it. If the map result is not empty, it returns Optional, otherwise it returns empty Optional r2 = op3.map((str) -> "hello->" + str); System.out.println(r2); //Similar to the map above, but you need to encapsulate yourself as Optional in the map function. Optional res = op3.flatMap((str) -> Optional.ofNullable("hello->"+str)); System.out.println(res); //If the value exists, it returns; otherwise, it returns other values, which is equivalent to the default value. Optional<String> op4 = Optional.ofNullable(null); System.out.println(op4.orElse("haha")); op4 = Optional.ofNullable("hello"); System.out.println(op4.orElse("haha")); //The function is similar to orElse above, except that it can use lambda expressions to handle the returned default values more flexibly Optional<String> op5 = Optional.ofNullable(null); System.out.println(op5.orElseGet(() -> String.valueOf(true))); //If the value exists, the lambda expression is executed. Otherwise, no processing is done and it does not return a value. Optional<String> op6 = Optional.ofNullable("itxiaoshen"); op6.ifPresent((str) -> System.out.println(str)); System.out.println("Separate output------------"); op6 = Optional.ofNullable(null); op6.ifPresent((str) -> System.out.println(str)); } }
Application examples
There are Squad, Platoon and Company
package cn.itxs.optional; public class Squad { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
package cn.itxs.optional; public class Platoon { private Squad squad; public Squad getSquad() { return squad; } public void setSquad(Squad squad) { this.squad = squad; } }
package cn.itxs.optional; public class Company { private Platoon platoon; public Platoon getPlatoon() { return platoon; } public void setPlatoon(Platoon platoon) { this.platoon = platoon; } }
Test class
package cn.itxs.optional; import java.util.Optional; public class OptionalDemo { public static void main(String[] args) { //It turns out that obtaining the name value of square requires multiple if statements Company company = new Company(); String name = null; if (null != company){ if (null != company.getPlatoon()){ if (null != company.getPlatoon().getSquad()){ name = company.getPlatoon().getSquad().getName(); } } } name = Optional.ofNullable(company) .map(c -> c.getPlatoon()) .map(p -> p.getSquad()) .map(s -> s.getName()) .orElse("I am a regiment"); System.out.println(name); } }
Streaming programming
summary
- Streaming programming is a new feature in 1.8. It performs pipeline like operations on set class data based on four commonly used functional interfaces and Lambda expressions. Using stream streaming programming can not only simplify code development and enhance readability, but also filter and map data without modifying the original set.
- Flow programming is divided into three steps: obtaining flow → operating flow → returning operation results.
- Get the data source and read the data in the data source into the stream.
- Various operations are performed on the data in the stream and the stream object itself is returned. Such operations are called - intermediate operations.
- You can perform various processing on the data in the stream and close the stream. Such an operation is called - terminate operation.
- In the intermediate operation and final operation, almost all method parameters are functional interfaces, which can be implemented by lambda expressions. Using set flow programming to simplify the amount of code requires proficiency in lambda expressions.
- In Java util. Stream package (java.util.stream.Stream), but it is not a functional interface. The interface contains many abstract methods. These methods are very important for stream operation. The most common methods are filter, map, foreach, count, limit, skip and concat.
- Stream is an enhancement of collection operations. Stream is not an element of a collection, is not a data structure, and is not responsible for data storage. Flow is more like an iterator, which can traverse each element in a collection in one direction and is not recyclable.
- Usage scenario
- Sometimes, when you operate on elements in a collection, you need to use the results of other operations. In this process, the set of streaming programming can greatly simplify the number of codes. Read the data from the data source into a stream, and you can operate on the data in the stream (delete, filter, map...). The result of each operation is also a flow object. You can perform other operations on this flow.
Code example
Creation of flow
package cn.itxs.stream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.stream.Stream; public class StreamMain { public static void main(String[] args) { //Get streams from collections. All collections in Java are implementation classes under Collection. Methods to get streams are provided in the Collection interface List<Integer> list1 = new ArrayList<>(); Stream<Integer> stream1 = list1.stream(); // Get stream Stream<Integer> stream2 = list1.parallelStream(); // Get stream (multithreading, high efficiency under large amount of data) //Array to get the stream. Array Java provides an Arrays tool class. We can convert the array into a collection to get the stream Integer[] arr = {1, 2, 3, 4, 5}; List<Integer> list2 = Arrays.asList(arr); list2.forEach(str->System.out.print(str+";")); //lambda is written to print out list array elements Stream<Integer> stream3 = list2.stream(); Stream<Integer> stream4 = list2.parallelStream(); Stream<Integer> stream5 = Arrays.stream(arr); //Get the stream directly through the Arrays class Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5); //The static method of the Stream interface, of, can obtain the Stream corresponding to the array. The parameter of the of method is actually a variable parameter, so it also supports arrays Stream<Integer> stream7 = Stream.of(arr); Stream<Integer> stream8 = Stream.generate(() -> new Random().nextInt(10)); //The generate method returns an infinite continuous unordered flow, in which each element is generated by the supplier provided. The generate method is used to generate a constant flow and a random element flow Stream<Integer> stream9 = Stream.generate(() -> new Random().nextInt(10)).limit(3); //generate returns an infinite continuous stream. In order to limit the number of elements in the stream, we can use stream Limit method Stream<Integer> stream10 = Stream.iterate(0, i -> i + 2).limit(5); //Specify a constant seed to generate a stream from seed to constant f (the value returned by UnaryOperator). According to the starting value seed(0), a specified number of increment (i+2) is generated each time. limit(5) is used to truncate the length of the stream, that is, only the first 5 elements are obtained. } }
Stream operation
package cn.itxs.stream; import java.util.ArrayList; public class StreamMain { public static void main(String[] args) { ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee("Zhang San", 32, 'male', 8000)); list.add(new Employee("Li Ting", 36, 'female', 7000)); list.add(new Employee("Zhang San", 32, 'male', 8000)); list.add(new Employee("Guanhua", 32, 'male', 18000)); list.add(new Employee("Li Wu", 22, 'male', 2800)); list.add(new Employee("Zhang Haidong", 34, 'male', 12000)); list.add(new Employee("Zhang Anfu", 32, 'male', 8000)); list.add(new Employee("Jia Yi", 22, 'female', 21000)); list.add(new Employee("Fang Shuzhen", 26, 'female', 14800)); list.add(new Employee("Huang Shidi", 37, 'male', 26300)); System.out.println("filter------"); //filter filtering method list.stream() .filter(e -> e.getAge() > 32) .forEach(System.out::println); System.out.println("intercept------"); //Only get 5 pieces of data in the result (intercept from the first one) list.stream() .limit(3) .forEach(System.out::println); System.out.println("skip------"); //Two elements are skipped here list.stream() .skip(7) .forEach(System.out::println); System.out.println("duplicate removal------"); // For the de duplication operation, one of the two three objects is reserved list.stream() .distinct() .forEach(System.out::println); System.out.println("sort------"); // Sort collections by salary list.stream() .sorted((e1, e2)->Integer.compare(e1.getSalary(), e2.getSalary())) .forEach(System.out::println); System.out.println("transformation------"); // The name of each user is returned through the map, and the user set is changed into the user name set list.stream() .map(Employee::getName) .forEach(System.out::println); } }
Return operation result
The forEach used in the above section belongs to the code that returns the result. If only the filter method is called without calling the return result, the filter method will not be executed.
package cn.itxs.stream; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamMain1 { public static void main(String[] args) { ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee("Zhang San", 32, 'male', 8000)); list.add(new Employee("Li Ting", 36, 'female', 7000)); list.add(new Employee("Zhang San", 32, 'male', 8000)); list.add(new Employee("Guanhua", 32, 'male', 18000)); list.add(new Employee("Li Wu", 22, 'male', 2800)); list.add(new Employee("Zhang Haidong", 34, 'male', 12000)); list.add(new Employee("Zhang Anfu", 32, 'male', 8000)); list.add(new Employee("Jia Yi", 22, 'female', 21000)); list.add(new Employee("Fang Shuzhen", 26, 'female', 14800)); list.add(new Employee("Fang Shuzhen", 26, 'female', 14800)); list.add(new Employee("Huang Shidi", 37, 'male', 26300)); //Take the minimum value Employee employee = list.stream() .filter(item -> item.getSalary() > 8000) .min(Comparator.comparingInt(Employee::getSalary)) // The entity class can only be obtained after get ting .get(); System.out.println(employee); //Take the maximum value employee = list.stream() .filter(item -> item.getSalary() > 8000) .max(Comparator.comparingInt(Employee::getSalary)) .get(); System.out.println(employee); //Count results long count = list.stream() .filter(item -> item.getSalary() > 10000) .count(); System.out.println(count); //Return operation result List<Employee> collect = list.stream() .filter(item -> item.getSalary() > 10000) // Call the collect method directly, and then call toList to transform the result to the List set. .collect(Collectors.toList()); System.out.println(collect); //Combine two flows Stream<Integer> stream1 = Stream.of(11,22); Stream<Integer> stream2 = Stream.of(33,44); Stream<Integer> stream3 = Stream.concat(stream1, stream2); stream3.forEach(s->System.out.println(s)); //Comprehensive example List<String> result = list.stream() // Find all female employees .filter(item->item.getGender()=='female') // Remove duplicate data .distinct() // Sort by age .sorted(Comparator.comparingInt(Employee::getAge)) // Extract name .map(Employee::getName) // Convert to List collection .collect(Collectors.toList()); // Print view effect System.out.println(result); } }
**My blog website** IT God www.itxiaoshen.com