Java 1.8 streaming Computing: functional programming + Chain programming using interface
1. Flow calculation
reference resources
1) Underlying resolution of ArrayList and Stream Association (default method of Collection)
In java streaming computing, take the list set as an example. Because ArrayList and LinkedList implement the list interface, while the list interface inherits the Collection interface, and the Collection interface has a stream () method modified by the default keyword (the method can be implemented in the interface), the implementation class ArrayList inherits the default method (stream () of the Collection And the returned stream object can be obtained through a_list.stream().
//List interface public interface List<E> extends Collection<E> { ... } //ArrayList class public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ... } //Collection interface public interface Collection<E> extends Iterable<E> { ... @Override default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); } default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } }
Here is a bit of a detour. You should taste it carefully and pay attention to two knowledge points:
-
Because the object types added to the collection are uncertain, generics are used here, so that the Stream object types to be obtained also have generics.
-
The implementation class will inherit the default method in the interface, such as: https://blog.csdn.net/wf13265/article/details/79363522
public interface A { public default void a(){ System.out.println("This is A"); } } public class Test implements A{ } public class Main { public static void main(String[] args) { Test t = new Test(); t.a(); //Execute the default method in interface A } }
Here is a supplement:
-
The Collection object obtains the Stream object through the default stream() method in the Collection interface.
-
After all, Stream is an interface and needs an implementation class. It is clear that there is only one implementation class of Stream: ReferencePipeline.
This kind of object is mainly created in the default stream() in the Collection interface through the StreamSupport static method:
public final class StreamSupport { public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) { Objects.requireNonNull(spliterator); return new ReferencePipeline.Head<>(spliterator, StreamOpFlag.fromCharacteristics(spliterator), parallel); } }
2) Stream calculation
The Collection object obtains the stream object through the default stream() of the Collection, and then passes in four different types of functional interfaces (@ FunctionalInterface annotated interface) through the filter and other functions of the stream, and implements the only method to realize chain programming and complete the filtering (stream), sorting, mapping and final result (T) of the Collection object Output of.
public interface Stream<T> extends BaseStream<T, Stream<T>> { Stream<T> filter(Predicate<? super T> predicate); <R> Stream<R> map(Function<? super T, ? extends R> mapper); Stream<T> limit(long maxSize); void forEach(Consumer<? super T> action); }
Java 8 introduces Stream operation, which can realize parallel processing and functional operation of Collection. In the words of Zhou Yang's great God, SQL is JAVA, and JAVA is SQL. Use the Stream interface in the java.util.stream package to complete calculations, order by, where and other operations in SQL.
According to the results returned by operations, streaming operations are divided into intermediate operations and final operations. The final operation returns a specific type of result, while the intermediate operation returns the flow itself, so that multiple operations can be connected in series in turn. According to the concurrency of flow, flow can be divided into serial and parallel. Stream operation realizes the functions of collection filtering, sorting, mapping and so on.
reference resources Streaming computing in Java 8_ Yangyang blog - CSDN blog_ java streaming computing
Here's another wordy sentence: Stream is an interface, and Stream has only one implementation class, ReferencePipeline
In a case, find out the calculation method of Stream:
Filter by:
1. ID is even
2,age>23
3. name to uppercase
4. Alphabetical flashback by user name
5. Output only one user
public void streamCalcDemo() { User user1 = new User(1, 18, "lisa"); User user2 = new User(2, 19, "pika"); User user3 = new User(3, 20, "sandy"); User user4 = new User(4, 35, "alice"); User user5 = new User(6, 24, "flask"); List<User> list = Arrays.asList(user1, user2, user3, user4, user5); list.stream() .filter(u -> {return u.getId() % 2 == 0;}) //The filter parameter is .filter(u -> {return u.getAge() > 23; }) .map((u) -> { u.setName(u.getName().toUpperCase(Locale.ROOT)); return u; }) // compareTo() method in String class // Not very complex sorting does not need to implement the Comparator interface .sorted((u1,u2)->{return u2.getName().compareTo(u2.getName());}) .limit(1) .forEach(item->{ System.out.println(item.toString()); }); } @Data @ToString @AllArgsConstructor class User { private int id; private int age; private String name; }
2. Four functional interfaces (the core of flow computing)
reference resources
- Java - Stream streaming_ DJun's blog - CSDN blog
- Streaming computing in Java 8_ Yangyang blog - CSDN blog_ java streaming computing
- Java double colon (::) operator explanation
1) @ FunctionalInterface annotation & "::" symbol
The @ FunctionalInterface annotation is required for the internal interface of java8 lambda, which is an explanatory annotation
- An interface annotated by @ FunctionalInterface can only have one abstract method
- @Functional interface can only be used to annotate interfaces, not on class es and enumerations
- The regular interface annotated by @ functional interface can use lambda expression
public class Main { public static void main(String[] args) throws Exception { List<String> list = Arrays.asList("aaaa", "bbbb", "cccc"); list.forEach(s -> System.out.println(s)); //forEach passes in the consumer interface (input parameter, no return) } }
The interpretation of this symbol on the official website is method reference (functional programming), that is, referring to a method. The English name is Method References
lambda expressions can be used to create an anonymous method, which you need to implement yourself.
list.forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); list.forEach(s -> System.out.println(s)); //The above two methods are the same, and the following is the lambda expression
reference resources java8 gets the object with the maximum value of a field in the list object - Mark_ZSQ - brief book,
@Test public void test() { List<Sensor> sensorMongoList = Lists.newArrayList(); Sensor sensor = new Sensor(); sensor.setId("123123"); sensor.setNum("1"); sensorMongoList.add(sensor); Sensor sensorTwo = new Sensor(); sensorTwo.setId("3423423"); sensorTwo.setNum("2"); sensorMongoList.add(sensorTwo); Sensor sensor1 = sensorMongoList.stream().max(Comparator.comparing(Sensor::getNum)).get(); String num = sensor1.getNum(); num = String.valueOf(Integer.parseInt(num) + 1); System.err.println(num); }
The parameter of the comparing Function here is the Function interface
public static <T, U extends Comparable<? super U>> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor){ Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); }
Sensor::getNum represents the getNum method in the sensor class.
2)Function
Functional interface: there are input parameters and return values
//@detail @FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); }
public void testFunction() { // Writing before JDK1.8 Function<String, String> f1 = new Function<String, String>() { @Override public String apply(String s) { return s; } }; // Replace Lambda notation Function<String, String> f2 = (str) -> {return str;}; // Simplified writing Function<String, String> f3 = str -> str; System.out.println(f1.apply("hello")); System.out.println(f2.apply("hello")); System.out.println(f3.apply("hello")); } --- hello hello hello
3)Predicate
Deterministic interface: it has input parameters and returns Boolean values.
//@detail @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); }
public void testPredicate() { Predicate<String> predicate = s -> s.contains("abc"); System.out.println(predicate.test("helloabc")); } --- true
4) Consumer (no return)
Consumer interface: there are input parameters and no return value.
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); }
public void testConsumer() { Consumer<String> consumer = s -> System.out.println(s); consumer.accept("hello"); } --- hello
5) Supplier (with return)
Supply type interface: no parameters, only return values.
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
public void testSupplier() { Supplier<String> supplier = () -> "hello"; System.out.println(supplier.get()); } --- hello
3. Examples
/**Among the multiple optimal solutions, it is sorted according to other strategies, and the one with the highest score is selected*/ public OptimalSolWithStrategies getBestInOptimalSols(List<OptimalSolWithStrategies>os_list, List<Integer> cl_list) { List<Job> optimalSol = new ArrayList<Job>(); //Cascade filtering from the second policy for(int i=1; i < cl_list.size();i++) { if(cl_list.get(i) == 0){ float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getPriorityPer)).get().getPriorityPer(); List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>(); os_list.stream().filter(p->{return p.getPriorityPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//Less than max_ The optimal solution of Val exists temp_list os_list = temp_list; } else if(cl_list.get(i) == 1){ float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getNumPer)).get().getNumPer(); List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>(); os_list.stream().filter(p->{return p.getNumPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//Less than max_ The optimal solution of Val exists temp_list os_list = temp_list; } else if(cl_list.get(i) == 2){ float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getTimePer)).get().getTimePer(); List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>(); os_list.stream().filter(p->{return p.getTimePer() >= max_val;}).forEach(p-> {temp_list.add(p);});//Less than max_ The optimal solution of Val exists temp_list os_list = temp_list; } else if(cl_list.get(i) == 3){ float max_val = os_list.stream().max(Comparator.comparing(OptimalSolWithStrategies::getResolutionPer)).get().getResolutionPer(); List<OptimalSolWithStrategies> temp_list = new ArrayList<OptimalSolWithStrategies>(); os_list.stream().filter(p->{return p.getResolutionPer() >= max_val;}).forEach(p-> {temp_list.add(p);});//Less than max_ The optimal solution of Val exists temp_list os_list = temp_list; } } return os_list.get(0); }