Speaking of flow, we will think of mobile phones, computer assembly line, logistics warehouse commodity packaging line and so on. If mobile phones, computers and packages are regarded as the final results, various parts before processing goods can be regarded as data sources, while a series of processing operations in the middle can be regarded as stream processing.
The concept of flow
Java Se has input/output IO streams for streams, and The Stream introduced in Java8 is a new member of the Java API that allows you to handle collections of data declaratively. Stream provides a high-level abstraction of Java collection operations and expressions in an intuitive way similar to SQL statements querying data from a database. Note that the stream operation here can be thought of as processing set data.
Simply put, a stream is a data channel that manipulates sequences of elements produced by data sources (collections, arrays, files, and so on).
- The source – abandoned the use of a data source, such as collection, array, or input output resources |.
Streams generated from ordered sets retain the original order. A stream generated by a list with elements in the same order as the list
-
Element sequences – Just like collections, streams provide an interface to access an ordered set of values for a particular element type.
-
Data processing operations – The data processing capabilities of streams support database-like operations (data filtering, filtering, sorting, and so on).
-
Pipelining – Multiple stream operations themselves return a stream, and multiple operations can be linked together as a pipeline for data processing.
Flow & collection
- Period of calculation
The data in the collection is all calculated data, such as querying user records from the database in descending order by user ID and receiving user records through the list. The calculation of data has been completed before the collection is put into the collection.
The data in the stream is calculated according to the needs of users. For example, when searching through the search engine, the searched items are not all presented, and the top 10 or 20 items that most match are displayed first. Only after clicking “Next page”, the new 10 items will be output. The same is true for Stream computation, where the Stream evaluates data when the user needs it.
- External iteration versus internal iteration
If the collection is compared to the warehouse of a factory, the hardware of the factory is relatively backward at the beginning, and the goods need to be modified. At this time, workers go into the warehouse to process the goods and sometimes transfer the processed goods to another warehouse. At this point, it is necessary for developers to do the iteration themselves, find the needed goods one by one and deal with them, which is called external iteration.
When the factory developed and was equipped with assembly line operation, the factory only had to design the corresponding assembly line according to the demand, and then the workers only had to put the goods on the assembly line, and they could wait to receive the results, and the assembly line could also directly transport the goods to the corresponding warehouse according to the requirements.
This is called internal iteration, and the pipeline has done the iteration for you, you just have to say what to do (design the pipeline properly). The equivalent of Stream’s introduction of Java8 “automates” the processing of data.
Flow process
The entire flow operation is a pipeline on which elements are processed one by one. Note that many stream operations return a stream themselves, so multiple operations can be directly connected, as shown in the figure below. Operations can be chain-called, and parallel flows can also implement data stream parallel processing operations.
In general, the flow operation process is divided into three phases:
- create
Create a flow object with a data source
- In the middle of processing
Filtering, slicing, mapping, sorting and other intermediate operations
- Termination of the flow
Match, summarize, group, etc
The creation of a flow
For the convection operation, the corresponding flow should be created first, and the centralized form of the flow creation is as follows:
1 Collection creation flow
In Java 8, the collection interface has two methods to generate streams:
-
Stream () − Creates a serial stream for the collection.
-
ParallelStream () − Creates parallel streams for collections.
Example code is as follows:
Public static void main(String[] args) {/** * array <String> l1 = array. asList(" zhou ", "Zhou "," Zhou ", "Chow Yun-fat "); L1.stream (); L1.parallelstream (); l1.parallelstream (); }Copy the code
In addition to the basic operation of flow creation, there are several ways to create a flow.
2 value create stream
Stream.of(T…) : stream.of (“aa”, “bb”) generates a Stream
Stream<String> Stream = stream. of("java8", "Spring", "SpringCloud"); stream.forEach(System.out::println);Copy the code
Array creation stream
Create the corresponding stream based on the array type of the parameter.
-
Arrays.stream(T[ ])
-
Arrays.stream(int[ ])
-
Arrays.stream(double[ ])
-
Arrays.stream(long[ ])
/ array.stream (array.asList (10, 20, 30, 40).toarray ())); Stream = array.stream (arrays.asList (10, 20, 30, 40).toarray (), 0, 2);
4 File generation flow
stream = Files.lines(Paths.get("C:\\java\\jdbc.properties")); System.out.println(stream.collect(Collectors.toList())); Stream = files.lines (path.get ("C:\\ Java \\jdbc.properties"), charset.forname (" utF-8 ")); System.out.println(stream.collect(Collectors.toList()));Copy the code
5 Functions generate streams
Two methods:
-
Iterate: Applies the function to each newly generated value in turn
-
Generate: Accepts a function and generates a new value
// Weight 100 starts to generate even Stream. Iterate (100, n -> n + 2); Generate (() ->(int) (math.random () * 100 + 1));
Mid-stream operation
The intermediate operations of a stream fall into three main categories: filter slicing, map, and sort.
Filter slicing: An operation to filter elements similar to where criteria in SQL
Mapping: Transforms the result of an element. The advantage is similar to the meaning of a SELECT field or transforms the content of an element
Sort: easy to understand, commonly used IN SQL according to the field ascending order descending operation
Data preparation for intermediate flow operations (order data processing is taken as an example)
@datapublic class Order {// Order id private Integer ID; // order userId private Integer userId; Private String orderNo; // orderDate private Date orderDate; // Private String address; Private Date createDate; // Update time private Date updateDate; // Order status 0- Unpaid 1- Paid 2- To be shipped 3- Shipped 4- Received 5- Completed private Integer status; 1- Valid order 0- Invalid order private Integer isValid; Private Double total; }Order order01 = new Order(1, 10, "20190301", new Date(), new Date(), new Date(), 4, 1, 100.0); Order order02 = new Order(2, 30, "20190302", new Date(), new Date(), new Date(), new Date(), 1, 1, 2000.0); Order03 = new Order(3, 20, "20190303", new Date(), New Date(), new Date(), 4, 1, 500.0); Order order03 = new Order(3, 20, "20190303", New Date(), New Date(), new Date(), 4, 1, 500.0); Order04 = new Order(4, 40, "20190304", new Date(), New Date(), new Date(), 4, 1, 256.0); order04 = New Order(4, 40, "20190304", New Date(), New Date(), new Date(), 4, 1, 256.0); Order order05 = new Order(5, 40, "20190304", new Date(), New Date(), new Date(), 4, 1, 1000.0); Order order05 = new Order(5, 40, "20190304", New Date(), new Date(), 4, 1, 1000.0); ordersList = Arrays.asList(order01, order02, order03, order04, order05);Copy the code
Screening & slicing
-
Screening valid orders
Orderslist.stream ().filter((order) -> order.getisValid () == 1).foreach (system.out ::println);
-
Filter valid orders and take the first page of data (2 records per page)
Orderslist.stream ().filter((order) -> order.getisValid () == 1).limit(2) .forEach(System.out::println);
-
Filter order collection valid order takes the last record
Orderslist.stream ().filter((order) -> order.getisValid () == 1).skip(orderslist.size () – 2) // Skip the former orderslist.size ()-2 record.foreach (system.out ::println);
-
Filter valid orders and take data on page 3 (2 records per page)
Orderslist.stream ().filter((order) -> order.getisValid () == 1).skip((3-1) * 2) .limit(2) .forEach(System.out::println);
-
Filter invalid orders to remove duplicate order number records
Orderslist.stream ().filter((Order) -> order.getisValid () == 0) .distinct() .forEach(System.out::println);
mapping
-
Filter valid orders to get all order numbers
// Filter valid orders, Orderslist.stream ().filter((order) -> order.getisValid () == 1).map((order) -> order.getorderno ()) .forEach(System.out::println);
-
Filter valid orders and separate the shipping address area information for each order
ordersList.stream().map(o -> o.getAddress() .split(“-“)) .flatMap(Arrays::stream) .forEach(System.out::println);
The sorting
-
Filter valid orders to sort by user ID
Orderslist.stream ().filter((order) -> order.getisValid () == 1).sorted((o1, o2) -> o1.getUserId() – o2.getUserId()) .forEach(System.out::println); Orderslist.stream ().filter((order) -> order.getisValid () == 1) .sorted(Comparator.comparingInt(Order::getUserId)) .forEach(System.out::println);
-
Filter valid orders and sort by order status if order status is the same sort by order creation time
Orderslist.stream ().filter((order) -> order.getisValid () == 1).sorted((o1, o2) -> { if (o1.getStatus().equals(o2.getStatus())) { return o1.getCreateDate().compareTo(o2.getCreateDate()); } else { return o1.getStatus().compareTo(o2.getStatus()); }}) .forEach(System.out::println); Orderslist.stream ().filter((order) -> order.getisValid () == 1).sorted(Comparator.comparing(order ::getCreateDate)) .thenComparing(Comparator.comparing(Order::getStatus))) .forEach(System.out::println);
The termination operation of a stream
Termination operations generate results from the pipeline of the flow. The result is any value that is not a stream, such as the usual List, Integer, and even void results. Termination operations for streams fall into the following three categories:
Find and match
-
Filter whether valid order matches are all paid orders
Println (“allMatch match result :” + orderslist.stream ().filter((order) -> order.getisValid () == 1) .allMatch((o) -> o.getStatus() ! = 0));
-
Filter valid order matches for unpaid orders
Println (“anyMatch match result :” + orderslist.stream ().filter((order) -> order.getisValid () == 1) .anyMatch((o) -> o.getStatus() == 0) );
-
Filter valid orders all outstanding orders
System.out.println(“noneMatch matching result :” + orderslist.stream ().filter((order) -> order.getisValid () == 1) .noneMatch((o) -> o.getStatus() == 5) );
-
Filter the valid order to return the first order
Println (“findAny match result :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .findAny() .get() );
-
Filter all valid orders to return total orders
System.out.println(“count result :” + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .count() );
-
Filter valid order return amount Maximum order amount
System.out.println(” order Max :” + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .map(Order::getTotal) .max(Double::compare) .get() );
-
Filter valid order return amount Minimum order amount
System.out.println(” order minimum :” + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .map(Order::getTotal) .min(Double::compare) .get() );
Reduction & collection
1 reduction
The operation of repeatedly combining elements in a stream to obtain a value
-
Calculate the total amount of valid order
System.out.println(” orderslist.stream ().filter((order) -> order.getisValid () == 1)) .map(Order::getTotal) .reduce(Double::sum) .get() );
2 Collector Data collection
To transform the Stream into something else, the Coollect method acts as a terminal operation, receiving an implementation of the Collector interface that summarizes the elements in the Stream. The most common method is to collect all elements of a stream into a List, Set, or Collection.
3 Collection
Common collection collection methods toList, toSet, toCollection, toMap, etc
-
Filter all valid orders and collect the order list
Orderslist.stream ().filter((order) -> order.getisValid () == 1).collect(Collectors. ToList ()) .forEach(System.out::println);
-
Filter all valid orders and collect order numbers and order amounts
Map<String,Double> Map = orderslist.stream ().filter((order) -> order.getisValid () == 1). collect(Collectors.toMap(Order::getOrderNo, Order::getTotal)); Map.foreach ((k,v)->{system.out. println(“k:”+k+”:v:”+v); });
PS: get Java learning materials and tutorials, lezijie007 (code 999)
summary
Summary operations are common in Stream operations, such as calculating totals and averaging. Common methods are as follows:
Related operations are as follows
-
Filter all valid orders to return total orders
System.out.println(“count result :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .collect(Collectors.counting()) ); System.out.println(“count result :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1).count());
-
Return the total order amount
System.out.println(” order sum :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .collect(Collectors.summarizingDouble(Order::getTotal)) ); System.out.println(” order sum :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .mapToDouble(Order::getTotal) .sum() ); System.out.println(” order total amount :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1).map(order ::getTotal) .reduce(Double::sum) .get() );
-
Returns the average amount spent per valid order with user ID =20
System.out.println(” orderslist.stream () + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .filter((order -> order.getUserId()==20)) .collect(Collectors.averagingDouble(Order::getTotal)) ); System.out.println(” orderslist.stream () + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .filter((order -> order.getUserId()==20)) .mapToDouble(Order::getTotal) .average() .getAsDouble() ); System.out.println(” orderslist.stream () + orderslist.stream ().filter((order) -> order.getisValid () == 1)) .filter((order -> order.getUserId()==20)) .collect(Collectors.summarizingDouble(Order::getTotal)) .getAverage() );
-
Filter all valid orders and calculate the total order amount
System.out.println(” order sum :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .collect(Collectors.summingDouble(Order::getTotal)) );
The most value
-
Filter all valid orders and calculate the minimum order amount
System.out.println(” minimum order amount :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1).map(order ::getTotal) .collect(Collectors.minBy(Double::compare)) );
-
Filter all valid orders and calculate the maximum order amount
System.out.println(” maximum order amount :”+ orderslist.stream ().filter((order) -> order.getisValid () == 1)) .map(Order::getTotal) .collect(Collectors.maxBy(Double::compare)) );
Grouping & Partitioning
1 group
GroupingBy is used to group data, and finally returns a Map. The second parameter of groupingBy is used to implement multi-level grouping
-
Group operations based on valid order payment status
Map<Integer,List> g01=ordersList.stream() .filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getStatus)); g01.forEach((status,order)->{ System.out.println(“—————-“); System.out.println(” order status :”+status); order.forEach(System.out::println); });
-
Filter valid orders, grouping by user ID and payment status
Map<Integer,Map<String,List>> g02= ordersList.stream() .filter((order) -> order.getIsValid() == 1) GroupingBy (Order::getUserId, Collectors. GroupingBy ((o)->{if(O.gottStatus ()==0){return “not paid “; }else if (o.gestatus ()==1){return “paid “; }else if (o.gestatus ()==2){return “to be sent “; }else if (o.gestatus ()==3){return “geStatus “; }else if (o.gestatus ()==4){return “received “; } else{return “done “; }}))); G02. ForEach ((userId, m) – > {System. Out. Println (” user id: “+ userId +” — — > effective order is as follows: “); M. orEach ((status, OS) – > {System. Out. Println (” : “+ status +” – order list as follows: “); os.forEach(System.out::println); }); System.out.println(“———————–“); });
2 partitions
The difference between partitioning and grouping is that partitions are divided according to true and false, so the lambda accepted by partitioningBy is also T -> Boolean
-
Partition operation – Filter valid orders with order amount >1000
Map<Boolean,List> g03= ordersList.stream() .filter((order) -> order.getIsValid() == 1) .collect(Collectors.partitioningBy((o)->o.getTotal()>1000)); G03. ForEach ((b, OS) – > {System. Out. Println (” partition results: “a + b +” – results of a list: “); os.forEach(System.out::println); });
-
Splice operation – Filter valid orders and splice them
String orderStr=ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getOrderNo) .collect(Collectors.joining(“,”)); System.out.println(orderStr);
The application of flow
Java8 introduced Stream operation, making the processing of elements more convenient and fast, through the Stream provided by the relevant method is a good combination of Lambda, functional interface, method reference and other related content, making the Stream processing compared with the original collection processing code greatly simplified, Stream support function chain call, The code is more compact and the parallelization of elements supported by Stream improves the performance of the program.
The application of Stream is usually in the data processing of collection elements, especially in the case of multiple processing of elements. At the same time, the taste of functional programming is stronger, which is also a trend of future development.
Java8 core features Stream Stream introduction here, should be very detailed, I hope you enjoy.