"Lazy" operation of stream type in Java 8

Source: Internet
Author: User
Tags first string

Before we get to the point, we need to introduce two very important actions for the stream type in Java 8:

Intermediate and end Operations (intermediate and Terminal operation)

There are two types of methods for stream types:

    • Intermediate operation (Intermediate operation)
    • End operation (Terminal operation)

The official document gives a description of [skip the letter if you don't want to see it]:

Stream operations is divided into intermediate and terminal operations, and is combined to form stream pipelines. A stream pipeline consists of a source (such as a Collection, an array, a generator function, or an i/O Channel); followed by zero or more intermediate operations such as Stream.filter or stream.map; and a terminal operation such as Stream.foreach or Stream.reduce.Intermediate operationsreturnANewStream. They is always lazy; Executing an intermediate operation such as filter () does not actually perform any filtering, but instead creates aNewstream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not to begin until the terminal operation of the pipeline is executed. Terminal operations, such as Stream.foreach or intstream.sum, may traverse the Stream to produce a result or a side-effect. After the terminal operation is performed, the stream pipeline are considered consumed, and can no longer be used;ifYou need to traverse the same data source again and you mustreturnTo the data source to get aNewStream. In almost all cases, terminal operations is eager, completing their traversal of the data source and processing of the PI Peline before returning. Only the terminal operations iterator () and Spliterator () is not; These is provided as an "escape hatch" to enable arbitrary client-controlled pipeline traversals in the event that the existing operations is not sufficient to the task. Processing streams lazily allows forsignificant efficiencies;  In a pipeline such as the filter-map-sum example above, filtering, mapping, and summing can is fused into a single pass on The data, with minimal intermediate state. Laziness also allows avoiding examining all the data when it was not necessary; forOperations such as "find the first string longer than-characters", it is only necessary-examine just enough strings to find one, which has the desired characteristics without Examini ng all of the strings available from the source. (This behavior becomes even more important when the input stream was infinite and not merely large.)

In fact, after reading this official document, the whole person is very blindfolded, to tell you about the official document this paragraph exactly said something:

The first paragraph: the flow operation is divided into intermediate operations and end operations (as I have translated), these two operations plus the data source constitute the so-called pipeline, processing pipeline.

The second paragraph: says the middle operation will return a stream , the middle operation is lazy (lazy, what a lazy method, we will talk about later), and also with the filter to give an example, the implementation of the intermediate operation filter is not actually doing any filtering operation, but instead of creating a new stream, what does the new stream contain? Contains the elements that meet the filter criteria during the traversal of the original stream (initial stream) (oddly enough, isn't this a filtering operation?). How to Say no? It is important to note that intermediate operations do not start executing until the pipeline is executed (this will be discussed later in this section).

The third paragraph: People said, the end operation is eager, that is, to execute to the end of the operation I will start to traverse the data source and perform the intermediate operation of the process, will not wait for WHO. And once the end operation in pipeline is complete, then this pipeline mission is done, and if you have a new end operation, then I'm sorry, this old pipeline can't be used, you have to create a stream, and then build the wheel again. Here's a word I really don't understand what it means, "

Only the terminal operations iterator () and Spliterator () is not; These is provided as an "escape hatch" to enable arbitrary client-controlled pipeline traversals in theevent that th E Existing operations is not a sufficient to the task.

Also hope that the friends help explain, thank you!

Fourth paragraph: Praise the stream "lazy" the benefits of execution: high efficiency. The intermediate operations are fused together to minimize the state change of the object, and it also allows us to avoid unnecessary work, giving an example: in a bunch of strings, find the first string with more than 1000 characters, passing the stream Operation laziness so we don't have to traverse all the elements, just execute the action that can find the element that satisfies the condition (in fact, this requirement does not pass the stream pipeline can do it? In fact, the most important thing is that when faced with an infinite data source operation, its irreplaceable is manifested, because the classic Java collection is finite, of course, this is not our goal today, here does not expand the lecture.

Would like to have a little behind the document, said the middle operation is some holding state (stateful), some stateless (stateless), they are in the original data on the traversal of a number of different students interested in their own research, we today mainly look at the middle operation is how a "lazy" And how the "lazy" process is.

The secret of the "lazy" stream is that each time a stream is used, it connects multiple intermediate operations, and at the end, it attaches a closing action. Methods such as map () and filter () are intermediate operations, and when they are called, another stream object is returned immediately. For methods such as reduce () and FindFirst (), they are finalization operations that do not perform a real operation to obtain the desired value when they are called.

Starting from an example:

For example, when we need to print out the first uppercase name with a length of 3:

 Public classLazystreams {Private Static intLengthFinalString name) {System.out.println ("Getting length for" +name); returnname.length (); }    Private StaticString ToUpper (FinalString name) {System.out.println ("Converting to uppercase:" +name); returnname.touppercase (); }     Public Static voidMainFinalstring[] args) {List<String> names = arrays.aslist ("Brad", "Kate", "Kim", "Jack", "Joe", "Mike", "Susan", "George", "Robert", "Julia", " Parker "," Benson "); FinalString firstnamewith3letters =Names.stream (). Filter (NameLength (name) = = 3). Map (name-toUpper (name)). FindFirst (). get ();    System.out.println (firstnamewith3letters); }}

You may think that the above code will do a lot of work on the names collection, such as iterating through the collection first to get all the names of length 3, then traversing the collection of the filter and converting the name to uppercase. Finally, the first one is found from the collection of uppercase names and returned. This is also the classic case of Java eager processing angle. The order of processing at this time is this

For stream operations, a better code reading order is from right to left, or from bottom to top. Every operation is just right. If you read the above code in a eager perspective, it might perform a 15-step operation:

But this is not the case, do not forget the stream is very "lazy", it will not perform any unnecessary operations. In fact, the filter and map methods are actually triggered only when the FindFirst method is called. And filter will not be a breath of the entire set to implement filtering, it will be filtered, if the matching elements found, the element will be placed into the next intermediate operation, that is, the map method. So the actual situation is this:

\

The output from the console is this:

getting length for Bradgetting length for Kategetting length for Kimconverting to uppercase: KimKIM

In order to better understand the above process, we change the lambda expression to the classic Java notation, which is the form of an anonymous inner class:

FinalString firstnamewith3letters =Names.stream (). Filter (NewPredicate<string>{                 Public BooleanTest (String name) {returnLength (name) ==3; }}). map (NewFunction<string,string>{                 Publicstring Apply (string name) {returntoUpper (name);  }}). FindFirst (). get (); 

For implementation See:

It is easy to conclude that the filter and map methods are actually triggered only when the FindFirst method is called. And filter will not be a breath of the entire set to implement filtering, it will be filtered, if the matching elements found, the element will be placed into the next intermediate operation, that is, the map method.

When the end operation obtains the answer it needs, the entire calculation process is over. If you don't get the answer, it will require an intermediate operation to calculate more of the set elements until the answer is found or the entire collection is processed.

The JDK merges all intermediate operations into one, a process known as a fuse operation (fusing operation). So, in the worst case (that is, there are no elements in the collection that meet the requirements), the collection will only be traversed once, rather than performing multiple traversal as we would have imagined, perhaps answering the official document why "processing streams lazily allows for Significant efficiencies. "

To see what is happening at the bottom, we can split the operation of the stream above by type:

 stream<string> nameswith3letters = Names.stream (). Filter (Name - > Length (name) = = 3). Map (name -> ToUpper ( name)); System.out.println ( Stream created, filtered, mapped ...  ready to call FindFirst ... " final  String firstnamewith3letters = Nameswith3letters.findfirst (). get (); System.out.println (firstnamewith3letters);  
< Span class= "o" > < Span class= "NA" > //output results //Stream created, filtered, mapped ... //ready-to-call FindFirst ... //getting length for Brad//getting length for Kate//getting length For Kim//converting to Uppercase:kim//Kim       

Based on the results of the output, we can find that the intermediate operation is not executed after the intermediate operation is declared on the Strema object. Intermediate operations are performed only after the FindFirst () call has actually occurred.

Resources:

The master is lazy, the above example and the first two pictures from CSDN blogger Dm_vincent's Blog "[Java 8] (7) using the stream type of" lazy "operation"

"Lazy" operation of stream type in Java 8

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.