Java Stream Functional Programming Part 3: Pipeline Flow Result Processing

Keywords: Java Lambda SpringBoot

1. Java Stream Pipeline Data Processing

In the article written before this number, you were introduced to the Java Stream pipeline stream as a java API to simplify the handling of collection class elements.There are three stages in the process of use.Before starting this article, I feel that I still need to introduce these three stages to some new friends, as shown in Fig.

  • Phase 1 (blue in figure): Convert a collection, array, or line text file to a java Stream pipeline stream
  • Stage 2 (dashed line part in the diagram): Pipeline streaming data processing operations that process each element in the pipeline.The output element from the previous pipe acts as the input element for the next pipe.
  • Stage 3 (green in figure): Pipeline flow result processing operation, which is the core content of this article.

Before you begin, it is still necessary to review one of the examples that we have talked about before:

List<String> nameStrs = Arrays.asList("Monkey", "Lion", "Giraffe","Lemur");

List<String> list = nameStrs.stream()
        .filter(s -> s.startsWith("L"))
        .map(String::toUpperCase)
        .sorted()
        .collect(toList());
System.out.println(list);
  • The string List is first converted to a pipeline stream Stream using the stream() method
  • Pipeline data processing is then performed, first using the fliter function to filter all strings beginning with upperL, then converting the strings in the pipeline to upperCase, and then calling the sorted method to sort.The usage of these API s is described in the article before this number.lambda expressions and function references are also used.
  • Finally, the result is processed using the collect function to convert the java Stream pipeline stream to a List.The output of the final list is: [LEMUR, LION]

If you don't use java Stream pipeline streaming, think about how many lines of code do you need to complete the above functionality?Back to the main topic, this article is about the third stage: What can you do with the results of pipeline flow treatment?Let's get started!

2. ForEach and ForEachOrdered

If we just want to print out the Stream pipeline flow processing results instead of type conversion, we can use the forEach() method or forEachOrdered() method.

Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .parallel()
        .forEach(System.out::println);
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .parallel()
        .forEachOrdered(System.out::println);
  • The parallel() function means that elements in the pipeline are processed in parallel, not in series, which makes processing faster.However, this may result in subsequent elements being processed first in the pipeline flow, and subsequent elements being processed later, i.e., the order of elements cannot be guaranteed.
  • ForEachOrdered understands by name that although the order of data processing may not be guaranteed, the forEachOrdered method ensures that the order of element output is consistent with the order in which elements enter the pipeline flow.This is what follows (the forEach method does not guarantee this order):
Monkey
Lion
Giraffe
Lemur
Lion

3. Collection of elements

The most common use of java Stream is to convert a collection class into a pipeline flow, to process data for a pipeline flow, and to convert the results of a pipeline flow process into a collection class.The collect() method then provides us with the ability to convert the result of pipeline flow processing into a collection class.

3.1. Collect as Set

Collectors.toSet() method collects Stream's processing results, and all elements are collected into the Set collection.

Set<String> collectToSet = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) 
.collect(Collectors.toSet());

//The elements in the final collectToSet are: [Monkey, Lion, Giraffe, Lemur], note that the Set will weigh down.

3.2. Collect List

Similarly, elements can be collected into a List using the toList() collector.

List<String> collectToList = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toList());

// The elements in the final collectToList are: [Monkey, Lion, Giraffe, Lemur, Lion]

3.3. General collection methods

The element collection methods described above are specific.For example, Collectors.toSet() is used to collect collections of Set types; Collectors.toList() is used to collect collections of List types.Then, is there a more generic way to collect data elements that can be collected as any Collection interface subtype?
So, just like you've described a general way of collecting elements, you can collect data elements into any Collection type: by providing constructors to the required Collection types.

LinkedList<String> collectToCollection = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
).collect(Collectors.toCollection(LinkedList::new));

//The elements in the final collectToCollection are: [Monkey, Lion, Giraffe, Lemur, Lion]

Note: The code uses LinkedList::new, which actually calls the constructor of the LinkedList to collect elements into the Linked List.Of course, you can also use data elements such as LinkedHashSet::new and riorityQueue:: new to collect them as other collection types, which is more general.

3.4. Collected Array

Collect Stream's processing results through the toArray(String[]::new) method, collecting all elements into a string array.

String[] toArray = Stream.of(
   "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
) .toArray(String[]::new);

//The elements in the final toArray string array are: [Monkey, Lion, Giraffe, Lemur, Lion]

3.5. Collect Map s

Collectors.toMap() method is used to collect data elements into the Map, but there is a problem: whether elements in the pipeline act as keys or values.We used a Function.identity() method, which simply returns a lambda expression of "t-> t" (input is output).In addition, the distinct() pipeline flow processing function is used to ensure the uniqueness of the Map key values.

Map<String, Integer> toMap = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.distinct()
.collect(Collectors.toMap(
       Function.identity(),   //Element input is output, as key
       s -> (int) s.chars().distinct().count()// Enter a different number of letters for the element as value
));

// The result of the final toMap is: {Monkey=6, Lion=4, Lemur=5, Giraffe=6}   

3.6. Group Collection groupingBy

Collectors.groupingBy is used for grouping elements. The code below demonstrates how to collect different data elements into different lists based on their initials and encapsulate them as Map s.

Map<Character, List<String>> groupingByList =  Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur", "Lion"
)
.collect(Collectors.groupingBy(
       s -> s.charAt(0) ,  //Grouped by the first letter of an element, the same in a group
       // counting()//Add this line of code to achieve grouping statistics
));

// Elements in the final groupingByList: {G=[Giraffe], L=[Lion, Lemur, Lion], M=[Monkey]}
//If counting() is added, the result is: {G=1, L=3, M=1}

4. Other Common Methods

boolean containsTwo = IntStream.of(1, 2, 3).anyMatch(i -> i == 2);
// Determine if there is 2 in the pipe and the result is: true

long nrOfAnimals = Stream.of(
    "Monkey", "Lion", "Giraffe", "Lemur"
).count();
// Total Element Data in Pipeline Result nrOfAnimals: 4


int sum = IntStream.of(1, 2, 3).sum();
// Element Data Accumulation in Pipeline Result sum: 6


OptionalDouble average = IntStream.of(1, 2, 3).average();
//Average value of element data in pipeline average: OptionalDouble[2.0]



int max = IntStream.of(1, 2, 3).max().orElse(0);
//Maximum max: 3 for element data in pipeline



IntSummaryStatistics statistics = IntStream.of(1, 2, 3).summaryStatistics();
// Overall statistics: IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}

Looking forward to your attention

Posted by Whitestripes9805 on Mon, 11 Nov 2019 16:42:47 -0800