Java Stream Usage Explained

Source: Internet
Author: User

Stream is a newly added class of Java 8 that complements the collection class.

The stream represents the data stream, and the number of data elements in the stream can be limited or infinite.

The difference between stream and other collection classes is that other collection classes focus primarily on access and effective management of limited amounts of data (pruning), and that stream does not provide access to and manage elements, but rather uses computable operations to execute on the data source by declaring the data source, Of course, the Basestream.iterator () and Basestream.spliterator () operations provide a way to iterate through the elements.

Java stream provides both serial and parallel types of streams, maintains a consistent interface, provides functional programming, provides intermediate operations and final execution in a piped manner, provides a similar high-level function operation for a collection of Java languages, simplifies and improves the functionality of the Java collection.

This article first introduces the characteristics of Java stream, then describes the intermediate and endpoint operations of the stream by functional classification, and finally introduces the third-party extensions for Java stream.

At the end of the year, I wrote some articles about the Java 8 Lambda and stream, which should be done at that time. I was busy with the project and writing the Scala Collection Technical Handbook (Scala collections Cookbook), which has never had time to write a Java stream article, and now this article is a summary of Java stream.

Introduced

This section is translated and collated from Javadoc, and these characteristics of convection are further explained.

The stream interface also contains several basic types of sub-interfaces such as Intstream, Longstream, and Doublestream.

For specific differences in flow and other collections, you can refer to the following list:

    1. No data is stored. A stream is an object based on a data source that itself does not store data elements, but instead passes the elements of the data source to the operation through a pipeline.
    2. Function-type programming. The operation of the stream does not modify the data source, such as filter does not delete data from the data source.
    3. Deferred operation. Many operations, such as Filter,map, are deferred, and only the operation sequence is performed by the end operation.
    4. can be untied. For an unlimited number of flows, some operations can be done in a limited amount of time, such as limit (n) or FindFirst (), which are "shorted" (short-circuiting), and can be returned after accessing limited elements.
    5. Pure consumption. The elements of the stream can only be accessed once, like iterator, without backtracking, if you want to re-access the elements of the stream from the beginning, I'm sorry, you have to regenerate a new stream.

The operation of the stream is strung together in a pipe way. The flow pipeline contains a data source, which then contains 0 to n intermediate operations and ends with an end-of-operation.

Parallel Parallelism

All flow operations can be executed serially or in parallel. The Java library creates a serial stream unless the parallel stream is created in the display. Collection.stream () creates a serial stream for the collection and Collection.parallelstream () creates a parallel stream for the collection. Intstream.range (int, int) creates a serial stream. The parallel () method can be used to convert the serial flow into parallel streams, and the sequential () method converts the flow into parallel streams.

The results of serial and parallel execution should be the same unless the method's Javadoc indicates that the result is indeterminate (such as Findany, ForEach) in parallel execution.

Non-interference non-interference

A stream can be created from a non-thread-safe collection, and a non-concurrent data source should not be altered when the stream's pipeline executes. The following code throws a Java.util.ConcurrentModificationException exception:

list<string> L = new ArrayList (Arrays.aslist ("One", "one"); stream<string> SL = L.stream (), Sl.foreach (S-l.add ("three"));

In the middle of the operation, you can change the data source, only when the end operation is performed, it is possible to have concurrency problems (throwing exceptions, or undesirable results), such as the following code does not throw an exception:

list<string> L = new ArrayList (Arrays.aslist ("One", "one"); stream<string> SL = L.stream (); L.add ("three"); Sl.foreach (System.out::p rintln);

For concurrent data sources, there is no such problem, such as the following code is normal:

list<string> L = new copyonwritearraylist<> (Arrays.aslist ("One", "one"); stream<string> SL = L.stream (), Sl.foreach (S-l.add ("three"));

Although the above example is a non-concurrent data source modification in the endpoint operation, the non-concurrent data source may also be modified in other threads, as well as concurrency problems.

Stateless stateless behaviors

The parameters for most of the flow's operations are functional interfaces, which can be implemented using lambda expressions. They are used to describe the behavior of the user, called the behavior parameter (behavioral parameters).

If these behavior parameters have a state, the result of the flow operation may be indeterminate, such as the following code:

list<string> L = new ArrayList (Arrays.aslist ("One", "one", "...)"); Class State {    Boolean s;} Final state state = new State (); stream<string> SL = L.stream (). Map (E, {    if (STATE.S)        return "OK";    else {        state.s = true;        return e;    } }); Sl.foreach (System.out::p rintln);

The above code can be executed several times in parallel when executing the result may be different. This is because the lambda expression is stateful.

Side Effects Side-effects

Behavioral parameters that have side effects are encouraged to be used.

Side effects refer to the input input of the behavior parameters at execution time, such as network input and output.

This is because Java does not guarantee that these side effects are visible to other threads, nor does it guarantee that different operations of the same elements on the same stream pipeline run in the same thread.

Many behavioral parameters that have side effects can be converted into non-side-effect implementations. In general println () such side-effects code is not harmful.

arraylist<string> results = new arraylist<> () Stream.filter (S-pattern.matcher (s). Matches ())      . ForEach (S-results.add (s));  Side-Effect Code

The above code can be changed to no side effects.

List<string>results =    Stream.filter (S-pattern.matcher (s). Matches ())          . Collect ( Collectors.tolist ());  No side-effects!
Sort Ordering

Some of the returned elements of a stream are in a definite order, which we call encounter order. This order is the order in which the stream provides its elements, such as the encounter order of the array, which is the sort order of its elements, the list is its iteration order (iteration order), and for HashSet, it has no encounter order.

Whether a stream is a encounter order relies primarily on the data source and its intermediate operations, such as the data source list and the stream created on the array is ordered (ordered), but the flow created in HashSet is not ordered.

The sorted () method can change the flow into an orderly, unordered can change the flow into disorder. In addition, an operation may affect the flow of the order, such as the map method, it will be different values and even type to replace the elements in the stream, so the order of the input element has become meaningless, but for the filter method, it just discard some values, the INPUT element order is guaranteed.

For a serial stream, the flow order does not affect its performance, it only affects certainty (determinism), and unordered streams may result in different results when executed multiple times.

For parallel streams, removing the ordered constraint may provide performance, such as distinct, groupingby, and the aggregation operations.

Associativity of binding

An operation or function op satisfies the binding meaning that it satisfies the following conditions:

(a op b) op c = = a op (b op c)

For concurrent flows, if the operation satisfies the binding, we can calculate it in parallel:

A Op b op c op d = = (a op b) OP (c op d)

For example, Min, max, and string connections are all binding.

Create stream

There are several ways to create a flow:

1, through the stream () method of the collection or Parallelstream (), such as Arrays.aslist (). Stream ().

2, through the Arrays.stream (object[]) method, such as Arrays.stream (new int[]{1,2,3}).

3, static method of using the flow, such as Stream.of (object[]), intstream.range (int, int) or stream.iterate (Object, Unaryoperator), such as Stream.iterate (0, N, n * 2), or generate (supplier<t> s) such as Stream.generate (Math::random).

4. Bufferedreader.lines () Gets the stream of the row from the file.

5, the Files class operation path method, such as list, find, walk and so on.

6, random number stream random.ints ().

7. Some other classes provide methods for creating streams, such as Bitset.stream (), Pattern.splitasstream (Java.lang.CharSequence), and Jarfile.stream ().

8. The lower level uses Streamsupport, which provides a way to convert the spliterator into a stream.

Intermediate Operation Intermediate Operations

The intermediate operation returns a new stream, and the action is deferred (lazy), which does not modify the original data source and is actually executed when the endpoint operation starts. This Scala collection has a different conversion operation, and the Scala Collection transformation operation generates a new intermediate collection, which is obvious that Java's design reduces the generation of intermediate objects.

These intermediate operations of the stream are described below:

Distinct

Distinct guarantees that the output stream contains a unique element, which is checked by Object.Equals (Object) to include the same element.

list<string> L = stream.of ("A", "B", "C", "B")        . Distinct ()        . Collect (Collectors.tolist ()); System.out.println (l); [A, B, c]
Filter

The stream returned by filter contains only data that satisfies the assertion (predicate).

The following code returns an even collection in the stream.

list<integer> L = intstream.range (1,10)        . Filter (i-i% 2 = = 0)        . Boxed ()        . Collect ( Collectors.tolist ()); System.out.println (l); [2, 4, 6, 8]
Map

The map method maps the elements in the stream to another value, and the new value type can be different from the original element type.

The following code maps a character element to its hash code (ASCII value).

list<integer> L = stream.of (' A ', ' B ', ' C ').        map (c-, C.hashcode ())        . Collect (Collectors.tolist ()); System.out.println (l); [97, 98, 99]
Flatmap

The Flatmap method blends the functionality of the Map+flattern, which puts all the elements of the mapped stream into a new stream. Its method is defined as follows:

<R> stream<r> flatMap (function<? Super T,? extends Stream<? extends r>> Mapper)

You can see that the mapper function transforms each element into a stream object, and the stream that the Flatmap method returns contains elements of the mapper generated stream.

In the following example, a Tang poem is generated in a stream divided by rows, and then called Flatmap on this stream to get a lowercase collection of words, remove the duplicate words and print them out.

String poetry = "Where, before me, is the ages that has gone?/n" +        "and Where, behind me, is the coming generations ?/n "+        " I think of Heaven and earth, without limit, without end,/n "+        " and I am all alone and my tears fall down. " ; Stream<string> lines = Arrays.stream (Poetry.split ("/n")); stream<string> words = Lines.flatmap (line-Arrays.stream (Line.split (""))); list<string> L = Words.map (W, {    if (W.endswith (",") | | w.endswith (".") | | w.endswith ("?"))        Return w.substring (0,w.length ()-1). Trim (). toLowerCase ();    else        return W.trim (). toLowerCase ();}). Distinct (). Sorted (). Collect (Collectors.tolist ()); System.out.println (l); [Ages, all, alone, am, and, is, before, behind, coming, down, earth, end, fall, generations, gone, has, heaven, I, Lim It, me, my, of, tears, that, the, think, where, without]

Flatmaptodouble, Flatmaptoint, and Flatmaptolong provide a way to convert to a specific stream.

Limit

The Limit method specifies the number of elements of the stream. For a serial stream, this method is valid because it simply returns the first n elements, but it can take a relatively long time for an ordered parallel stream, and if you don't care about ordering, you can improve performance by converting ordered parallel streams to unordered.

list<integer> L = intstream.range (1,100). Limit (5)        . Boxed ()        . Collect (Collectors.tolist ()); System.out.println (l);//[1, 2, 3, 4, 5]
Peek

The Peek method method uses an element in a consumer consumption stream, but the returned stream still contains elements from the original stream.

string[] arr = new string[]{"A", "B", "C", "D"}; Arrays.stream (arr)        . Peek (system.out::p rintln)//a,b,c,d        . Count ();
Sorted

Sorted () Sorts the elements in the stream in a natural sort order, and if the element does not implement comparable, an Java.lang.ClassCastException exception is thrown when the endpoint operation executes. Sorted (comparator<? Super t> Comparator) can specify how the sort is sorted.

For ordered streams, the ordering is stable. For non-ordered flows, the ordering stability is not guaranteed.

string[] arr = new string[]{"b_123", "c+342", "b#632", "d_123"}; list<string> L  = arrays.stream (arr)        . Sorted ((S1,S2), {            if (s1.charat (0) = = S2.charat (0))                Return s1.substring (2). CompareTo (S2.substring (2));            else                return S1.charat (0)-S2.charat (0);        })        . Collect (Collectors.tolist ()); System.out.println (l); [B_123, b#632, c+342, d_123]
Skip

Skip returns a stream that discards the first n elements, or returns an empty stream if the element in the stream is less than or equal to N.

End Operation Terminal Operationsmatch
public boolean allmatch (PREDICATE<? Super t> predicate), public, Booleans AnyMatch (predicate<? Super T> predicate) Public boolean nonematch (PREDICATE<? Super t> predicate)

This set of methods is used to check whether an element in the stream satisfies the assertion.

Allmatch returns true only if all elements satisfy the assertion, otherwise flase always returns true if the stream is empty

AnyMatch returns true only if any element satisfies an assertion, otherwise flase,

Nonematch returns true only if all of the elements do not satisfy the assertion, otherwise flase,

System.out.println (Stream.of (1,2,3,4,5) Allmatch (i-i > 0)); True      System.out.println (Stream.of (1,2,3,4,5) AnyMatch (i-i > 0));//true      System.out.println ( Stream.of (1,2,3,4,5). Nonematch (i-i > 0)); FalseSystem.out.println (Stream.<integer>empty (). Allmatch (i-i > 0)); True      System.out.println (Stream.<integer>empty (). AnyMatch (I-> 0));//false      System.out.println (Stream.<integer>empty (). Nonematch (i-i > 0)); True
Count

The Count method returns the number of elements in the stream. It is implemented as:

Maptolong (e-1L). SUM ();
Collect
<R,A> R Collect (collector<? Super t,a,r> Collector) <R> R Collect (supplier<r> Supplier, Biconsumer<r, huh? Super t> Accumulator, biconsumer<r,r> combiner)

Use a collector to perform mutable reduction operations. Auxiliary class collectors provides a lot of collector to meet our daily needs, and you can create new collector to implement specific requirements. It is a noteworthy class that you need to familiarize yourself with these specific collectors, such as aggregate class averagingint, maximum minimum maxbyminby, count counting, group Groupingby, string connection joining, Partition Partitioningby, summarize summarizingint, simplify reducing, convert toxxx and so on.

The second provides a lower level of functionality, and its logic resembles the following pseudo-code:

R result = Supplier.get (); for (T element:this stream)    accumulator.accept (result, element); return result;

Example:

list<string> aslist = Stringstream.collect (Arraylist::new, Arraylist::add,                                           arraylist::addall); String concat = Stringstream.collect (Stringbuilder::new, Stringbuilder::append,                                     stringbuilder::append)                            . ToString ();
Find

Findany () returns any element that, if the stream is empty, returns an empty optional, it only needs to return any element for the parallel stream, so performance may be better than FindFirst (), but it is possible to return a different result when executed multiple times. FindFirst () returns the first element, if the stream is empty, returns an empty optional.

ForEach, foreachordered

foreach iterates through each element of the stream, executing the specified action. It is an endpoint operation, unlike the Peek method. This method is not guaranteed to be executed in the encounter order order of the stream, and you can use the Foreachordered method if the ordered stream is executed in its encounter order.

Stream.of (1,2,3,4,5). ForEach (System.out::p rintln);
Maximum minimum value

Max returns the maximum value in the stream, Min returns the minimum value in the stream.

Reduce

Reduce is a common method, and in fact many operations are implemented based on it. It has several overloaded methods:

Pubic optional<t> reduce (binaryoperator<t> accumulator) pubic t reduce (t identity, binaryoperator<t> ACCUMULATOR) Pubic <U> u reduce (u identity, Bifunction<u,? Super t,u> Accumulator, binaryoperator<u> combiner)

The first method uses the first value in the stream as the initial value, and the next two methods use a provided initial value.

optional<integer> total = Stream.of (1,2,3,4,5). reduce ((x, y), x +y), Integer total2 = Stream.of (1,2,3,4,5). Red UCE (0, (x, y), x +y);

It should be noted that accumulator should meet the binding (associative).

ToArray ()

Places the elements in the stream into an array.

Combination

The concat is used to connect two streams of the same type.

public static <T> stream<t> concat (stream<? extends t> a, stream<? extends t> b)

Transformation

The ToArray method converts a stream into an array, and if you want to convert to another collection type, the West needs to call the Collect method and use the Collectors.toxxx method to convert it:

public static <t,c extends collection<t>> collector<t,?, c> tocollection (supplier<c> collectionfactory) public static .... Toconcurrentmap (...). public static <T> collector<t,?, list<t>> toList () public static ... Tomap (...) public static <T> collector<t,?, set<t>> toset ()
Further

While stream provides a lot of action, it seems to be a little less than in languages like Scala. Some open source projects provide additional operations, such as the Protonpack project, which provides the following methods:

    • TakeWhile and Takeuntil
    • SkipWhile and Skipuntil
    • Zip and Zipwithindex
    • Unfold
    • Mapstream
    • Aggregate
    • Streamable
    • Unique collector

Java8-utils also offers some helpful ways to help.

Reference documents
    1. Https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
    2. http://www.leveluplunch.com/java/examples/
    3. Https://github.com/poetix/protonpack
    4. Https://github.com/NitorCreations/java8-utils

Java Stream Usage Explained

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.