First, stream experience
Stream is an important feature of the operations set in Java8, let's take a look at how the stream is defined in Java:
"A sequence of elements supporting sequential and parallel aggregate operations."
Let's read the above statement:
1, Stream is a collection of elements, which makes the stream appear to use some similar iterator;
2, can support sequential and parallel to the original stream aggregation operation.
You can think of stream as a premium version of iterator. The original version of the iterator, the user can only one one to traverse the element and perform certain operations on it; the advanced version of the stream, the user simply gives what they need to do with the elements they contain, such as "filter out strings longer than 10", "get the first letter of each string", etc. How do these actions apply to each element, and give the stream a good one! Everyone reading these may not have a visual understanding of the stream, MO, we come to the code.
// lists is a tool class in Guava List<integer> nums = lists.newarraylist (1,null, 3,4,null, 6); NULL
The above code is to get a list of the number of elements that are not NULL. Although this code is short, it is a good entry-level example of how to use stream, which is called "perfectly formed". We are now going to dig into this example and you may be able to master the usage of the stream in the future!
Parse Stream General syntax
The picture is an analysis of the stream example, it is clear to see: The original statement was a three-color box divided into three parts. The statement in the red box is the place where the stream's life begins, and is responsible for creating a stream instance; The statement in the green box is the place that gives the stream soul, converts a stream to another stream, The statement of the red box generates a stream containing all the nums variables, and after the filter method of the green box, it regenerates a stream that filters out all null in the original nums list; The statement in the blue box is where the harvest is, The content contained in the stream is aggregated into a value according to an algorithm, in which case the number of elements contained in the stream is obtained. If it is not understood after this analysis, it can only use "nuclear weapons"-graphical, a picture of thousands of words!
Here we summarize the basic steps for using stream:
1, create stream;
2, convert stream, each conversion of the original stream object does not change, return a new Stream object (* * can have multiple conversions * *);
3. The stream is aggregated (Reduce) to get the desired result.
Second, create stream
The most common way to create a stream is two ways:
Static Factory method via stream Interface (note: The Java8 interface can take a static method);
The default method via the collection interface (the default method: A new feature in Java8, which is a method with an implementation in the interface) –stream () converts a collection object to stream.
1. Use stream static method to create stream
(1) of method: There are two overload methods, one receives a variable length parameter, and one receives a single value.
stream<integer> Integerstream = Stream.of (1, 2, 3, 5); Stream<String> stringstream = Stream.of ("Taobao");
(2) Generator method: generates an infinite-length stream whose elements are generated by a given supplier (this interface can be viewed as an object's factory, each call returning an object of a given type)
Stream.generate (new supplier<double>() { @Override public Double Get ( ) { return math.random (); math.random ()); Stream.generate (math::random);
The three statements are all the same, using only the syntax that lambda expressions and methods refer to to simplify the code. Each statement actually generates an infinite stream of streams, where the values are random. this infinite-length stream is lazy-loaded, and generally this infinite-length stream will be used with the stream's limit () method.
(3) Iterate method: also generates an infinite length of stream, unlike generator, whose elements are generated repeatedly by invoking a user-specified function on a given seed value (seed). The elements contained therein can be considered as: Seed,f (Seed), F (seed) infinite loop
Stream.iterate (1, item, item + 1). Limit (+). ForEach (System.out::p rintln);
This code is to get a stream of a set of positive integers of infinite length, and then remove the first 10 prints. never forget to use the limit method, or you will print indefinitely.
2. Get stream through collection sub-class
This is shown in the first example of this article from the list object to get its corresponding stream object, if you look at Java Doc can find the collection interface has a stream method, so all its subclasses can get the corresponding stream object.
Public Interface extends Iterable<e> { // Other methods omit default stream<e> Stream () { return false ); }}
Third, convert stream
Converting a stream is actually converting a stream through some behavior into a new stream. There are several common conversion methods defined in the stream interface, which are explained in the following selection of common conversion methods.
1, distinct: for the elements contained in the stream deduplication (to the logical dependency element of the Equals method), the newly generated stream does not have duplicate elements;
Distinct method
2, Filter: for the elements contained in the stream using the given filter function for filtering operations, the newly generated stream contains only the elements that meet the criteria;
Filter Method:
The following code fragment uses the filter method to filter out an empty string:
List<string>strings = Arrays.aslist ("abc", "" "," BC "," EFG "," ABCD "," "," JKL "); // gets the number of empty strings int count = Strings.stream (). Filter (String, String.isempty ()). Count ();
3, Map: for the elements contained in the stream using the given conversion function for the conversion operation, the newly generated stream contains only the elements of the transformation generated. This method has three variant methods for the original type, namely Maptoint,maptolong and maptodouble. These three methods are also better understood, for example Maptoint is to convert the original stream into a new stream, and the elements in the newly generated stream are of type int. There are three variants that can dispense with the extra consumption of automatic boxing/unpacking;
Map method:
The map method is used to map each element to the corresponding result, and the following code fragment uses map to output the square number corresponding to the element:
list<integer> numbers = Arrays.aslist (3, 2, 2, 3, 7, 3, 5); // gets the corresponding square number list<integer> squareslist = Numbers.stream (). Map (i*i). Distinct (). Collect (Collectors.tolist ());
4. FlatMap: Similar to map, the difference is that each of its elements is converted to a Stream object, which compresses the elements in the stream into the parent collection;
Flatmap Method:
5. Peek: generates a new stream containing all the elements of the original stream, as well as a consumption function (consumer instance) that executes a given consumption function when each element of the new stream is consumed;
Peek Method:
6, limit: A stream truncation operation, get its first n elements, if the original stream contains the number of elements less than n, then get all its elements;
Limit method:
7. Skip: Returns a new stream that leaves the elements after the first n elements of the original stream, and returns an empty stream if the original stream contains fewer than n elements.
Skip method:
8. Comprehensive example
PackageCom.demo;Importjava.util.List;Importorg.junit.Test;Importcom.google.common.collect.Lists; Public classTeststream {@Test Public voidTest () {List<Integer> nums = lists.newarraylist (1, 1,NULL, 2,3,4,NULL, 5,6,7,8,9,10); System.out.println ("Sum is:" +nums.stream (). Filter (num, num!=NULL). Distinct (). Maptoint (Numnum*2). Peek (System.out::p rintln). Skip (2). Limit (4). sum ()); }}
Operation Result:
24681012sum is:36
This code illustrates all of the conversion methods described above (in addition to Flatmap), briefly explaining what this code means: Given an integer type list, get its corresponding stream object, then filter out the null, then go to the weight, and then multiply each element by 2, Then each element is consumed by printing itself, skipping the first two elements, and finally taking the first four elements to add and operate (explaining a lot, much like crap, because basically look at the method name to know what to do.) This is one of the great benefits of declarative programming! )。
9, performance issues
Some of the attentive classmates may have this question: in a stream for a number of conversion operations, each time the stream of each element of the transformation, and is executed several times, so that the time complexity is a for loop all operations are done in the N (number of conversions) times AH. In fact, this is not the case, the conversion operation is lazy, multiple conversion operations will only be in the aggregation operation (see below) when the fusion, a loop to complete. We can simply understand that there is a collection of operation functions in the stream, and each conversion operation is to put the conversion function into this set, loop the corresponding collection of the stream at the time of the aggregation, and then execute all the functions for each element.
Iv. Convergence (Reduce) Stream
Before we introduce the aggregation operation, let's look at the definition of Java doc:
Reduction forms such as SUM (), Max (), or count (). "
A simple translation: The aggregation operation (also known as folding) takes an element sequence as input, repeatedly uses a merge operation, and merges the elements of the sequence into a summarized result. For example, to find the sum or maximum of a list of numbers, or to accumulate these numbers into a list object. The stream interface has some common aggregation operations, such as reduce () and collect (), as well as some aggregation operations for specific purposes, such as SUM (), Max (), and count (). Note: The sum method is not available for all stream objects, only Intstream, Longstream, and Doublestream are instances.
Here is a two-part overview of the aggregation operation:
Variable aggregation: Accumulate input elements into a variable container, such as collection or StringBuilder;
Other aggregation: Except for the remainder of the mutable aggregation, it is not generally done by repeatedly modifying a mutable object, but by using the previous aggregation result as the next entry, again and again. such as Reduce,count,allmatch;
1. Variable Aggregation
There is only one method for a mutable aggregation: collect, as its name shows, it can collect the elements in the stream into a result container (such as collection). First look at the definition of the most common collect method (there are other override methods):
<R> R Collect (supplier<r> Supplier, biconsumerSuper t> Accumulator, Biconsumer<r, r> combiner);
Let's take a look at the meaning of these three parameters: Supplier Supplier is a factory function used to generate a new container; Biconsumer Accumulator is also a function to add elements from the stream to the result container; Biconsumer Combiner is also a function used to merge multiple result containers of intermediate states into one (which is used in concurrency). You look dizzy? Come to the section code!
List<integer> nums = lists.newarraylist (all,null, 2,3,4,null, 5,6,7,8,9,10); Listnullnew arraylist<integer>-List1.addall (List2));
The above code is a list of elements that are of type Integer, filtering out all of the null, and then collecting the remaining elements into a new list. Take a closer look at the three parameters of the Collect method, all in the form of a lambda function (* The above code can be simplified using a method reference, leaving the reader to think for themselves *).
- The first function generates a new ArrayList instance;
- The second function takes two arguments, the first is the ArrayList object generated earlier, and two is the element contained in the stream, and the function body is adding the elements in the stream to the ArrayList object. The second function is repeatedly called until the elements of the original stream are consumed;
- The third function also accepts two parameters, both of which are ArrayList types, and the function body is to add the second ArrayList all to the first one;
But the above collect method call is also a bit too complex, it's okay! Let's take a look at the Collect method another override version, which relies on [Collector].
Super T, A, r> collector);
That's a lot more refreshing! The good news is that JAVA8 also provided us with the Collector tool class –[collectors], which has already defined some static factory methods, such as: Collectors.tocollection () collected in collection, Collectors.tolist () collects into the list and Collectors.toset () is collected into the set. This static method still has many, here does not introduce each one, we can go directly to see Javadoc. Here's a look at the simplification of the code using collectors:
null). Collect (Collectors.tolist ());
2. Other aggregation
–reduce Method:The reduce method is very common, and the count,sum described later can be implemented using it. The reduce method has three override methods, this article describes two most commonly used, the last one left to the reader to learn. Consider the first form of the reduce method, whose method is defined as follows:
optional<t> reduce (binaryoperator<t> accumulator);
Accept a parameter of type Binaryoperator, we can use lambda expression when using.
@Test Public void test1 () { List<Integer> ints = lists.newarraylist (1,2,3,4,5,6,7,8,9,10); System.out.println ("INTs sum is:" + ints.stream (). reduce ((sum, item), SUM + item). get ());
Operation Result:
INTs sum is:55
You can see that the reduce method accepts a function that has two parameters, the first parameter is the return value of the last function execution (also known as the intermediate result), the second argument is the element in the stream, the function adds the two values, and the resulting and assigned values are assigned to the first parameter of the next execution of the function. Note that the first value of the first parameter is the first element of the stream, and the second argument is the second element of the stream * *. This method returns a value type of optional, which is a viable way to prevent NPE from appearing, which is described in detail in the following article, which is simply considered a container, which may contain 0 or 1 objects.
The result of this process visualization
The reduce method also has a very common variant:
t reduce (t identity, binaryoperator<t> Accumulator);
This definition is basically the same as described above, the difference is that it allows the user to provide a loop calculation of the initial value, if the stream is empty, return the value directly. And this method does not return optional because it does not have a null value. The following example is given directly, it is no longer explained.
@Test Public void test2 () { List<Integer> ints = lists.newarraylist (1,2,3,4,5,6,7,8,9,10); System.out.println ("INTs sum is:" + ints.stream (). Reduce (0, (sum, item), SUM + item));}
Operation Result:
INTs sum is:55
–count method: Gets the number of elements in the stream. Relatively simple, here is a direct example, do not explain.
@Test Public void test3 () { List<Integer> ints = lists.newarraylist (1,2,3,4,5,6,7,8,9,10); System.out.println ("ints count is:" + Ints.stream (). Count ());}
Operation Result:
INTs Count Is:10
– Search for related
–allmatch: is not all elements in the stream satisfy the given match criteria
Whether there is an element in the –anymatch:stream that satisfies the match condition
–findfirst: Returns the first element in the stream, if the stream is empty, returns an empty optional
–nonematch: Whether all elements in the stream do not meet the given match criteria
– Max and min: Returns the maximum | minimum value in the stream using the given comparer (Operator)
The following is an example of Allmatch and Max, and the rest of the method reader as an exercise.
Stream of Java8