Java8 handles Stream for the elegant posture of a collection

Preface

In Java, collections and arrays are data structures that we often use and need to add, delete, change, check, aggregate, statistics, filter and so on.By contrast, this is true in relational databases, but collection and array processing was not very convenient until Java 8.

However, this issue has been improved in Java 8, with the Java 8 API adding a new abstraction called Stream, which allows you to process data in a declarative way.Here's how to use Stream.In particular, the performance and principles of Stream are not the focus of this article. If you are interested, a separate article will follow.

1. Introduction to Stream

Stream provides a high-order abstraction of Java set operations and expressions using an intuitive way similar to querying data from a database using SQL statements.

The Stream API can greatly increase the productivity of Java programmers, allowing them to write efficient, clean, and concise code.

This style treats a collection of elements as a stream that is transported through the pipeline and can be processed on the nodes of the pipeline, such as filtering, sorting, aggregation, and so on.

Stream has the following features and advantages:

  • No storage.Stream is not a data structure, it is just a view of a data source, which can be an array, a Java container, an I/O channel, etc.
  • For functional programming.Any modification to Stream will not modify the data source behind it, such as filtering Stream will not delete the filtered elements, but will result in a new Stream without the filtered elements.
  • Lazy execution.Operations on Stream are not performed immediately, but only when the user really needs the results.
  • Consumability.Stream can only be "consumed" once, and once traversed it will fail, just like the iterator of a container, it must be regenerated to traverse again.

Let's take an example to see what Stream can do on earth:

In the example above, take some colored plastic balls as data sources, first filter out the red ones and melt them into random triangles.Then filter and delete the small triangles.Finally, the perimeter of the remaining graphics is calculated.

As illustrated above, there are three main critical operations for flow processing: flow creation, intermediate operation, and terminal operation.

2.Stream Creation

There are many ways to create streams in Java 8.

1. Create streams from existing collections

In Java 8, in addition to adding many Stream-related classes, the collection class itself has been enhanced by adding a stream method that converts a collection class into a stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream<String> stream = strings.stream();

Above, a stream is created from an existing List.In addition, there is a parallelStream method that creates a parallel stream for a collection.

This way of creating a Stream from a collection is also a common way.

2. Create Stream s

You can use the methods provided by the Stream class to directly return a stream of specified elements.

Stream<String> stream = Stream.of("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");

As in the above code, a Stream is created and returned directly through the of method.

3.Stream Intermediate Operations

Stream has many intermediate operations, which can be connected to form a pipeline. Each intermediate operation is like a worker on the pipeline. Every worker can process on the stream, and the result is still a stream.

Here is a list of common intermediate operations:

filter

The filter method is used to filter out elements by setting conditions.The following snippet uses the filter method to filter out empty strings:

List<String> strings = Arrays.asList("Hollis", "", "HollisChuang", "H", "hollis"); 
strings.stream().filter(string -> !string.isEmpty()).forEach(System.out::println); //Hollis, , HollisChuang, H, hollis

map

The map method is used to map each element to its corresponding result, and the following code snippet uses map to output the corresponding square number of elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().map( i -> i*i).forEach(System.out::println); //9,4,4,9,49,9,25

The following three ways of writing a map are the same:

List<String> numbers = Arrays.asList("3", "2", "2"); 
numbers.stream().map(i -> i.toUpperCase()).forEach(System.out::println);
System.out.println("----------");
numbers.stream().map(i -> {return i.toUpperCase();}).forEach(System.out::println);
System.out.println("----------");
numbers.stream().map(String::toUpperCase).forEach(System.out::println);
System.out.println("----------");

Description of double colon:

The usage of:: is used in jdk8.The double colon operation is called a method reference in Java and the format of the method reference is:

  Class name: Method name 

Case:

Expression:

person -> person.getAge();

Use double colons:

Person: : getAge

Expression:

new HashMap<>()

Use double colons:

HsahMap :: new

 

limit/skip

Limit returns the first n elements of Stream; skip throws away the first n elements.The following snippet factorizes four elements using the limit method:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().limit(4).forEach(System.out::println); //3,2,2,3

 

sorted

The sorted method is used to sort streams.The following snippets are sorted using the sorted method:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().sorted().forEach(System.out::println);
//2,2,3,3,3,5,7

 

distinct

Distinct is mainly used for de-weighting. The following code snippets use distinct to de-weigh elements:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
numbers.stream().distinct().forEach(System.out::println);
//3,2,7,5

 

Next, we demonstrate what happens when a Stream is processed by filter, map, sort, limit, and distinct through an example and a graph.

The code is as follows:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis", "Hello", "HelloWorld", "Hollis");
Stream s = strings.stream()
   .filter(string -> string.length()<= 6)
   .map(String::length).sorted().limit(3)
   .distinct();

 

The process and the results from each step are as follows:

4.Stream Final Operations

The result of Stream's intermediate operation is still a Stream, so how can we convert a Stream to the type we need, such as counting the number of elements in the stream, swapping streams into collections, and so on.This requires a final operation

The final operation consumes the flow and produces a final result.That is, after the final operation, you cannot reuse the stream or use any intermediate operation, or you will throw an exception:

java.lang.IllegalStateException: stream has already been operated upon or closed

As the saying goes, "You never step into the same river twice." That's what it means.

Common final actions are as follows:

forEach

Stream provides the method'forEach'to iterate over each data in the stream.The following code snippet uses forEach to output 10 random numbers:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

 

count

Count is used to count the number of elements in the stream.

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
System.out.println(strings.stream().count());
//7

 

collect

A collect is a reduction operation that accepts various practices as parameters to accumulate elements in a stream into a summary:

List<String> strings = Arrays.asList("Hollis", "HollisChuang", "hollis","Hollis666", "Hello", "HelloWorld", "Hollis");
strings = strings.stream().filter(string -> string.startsWith("Hollis")).collect(Collectors.toList());
System.out.println(strings);
//Hollis, HollisChuang, Hollis666, Hollis

 

Next, let's use a diagram to show how a Stream, in the previous example, uses different final operations after it has been filter ed, map ped, sort, limit, and distinct.

The following figure shows the location, input, output, and results of all the operations described in this paper using a case study.

5. Summary

This paper introduces the use and advantages of Stream in Java 8.Several uses of Stream have also been accepted, namely Stream creation, intermediate operation, and final operation.

Stream is created in two ways, through the stream method of the collection class and through the off method of Stream.

Stream's intermediate operations can be used to process Stream. The input and output of the intermediate operations are Stream. The intermediate operations can be filtering, transforming, sorting, and so on.

The Stream's final action converts Stream into other forms, such as calculating the number of elements in the stream, swapping the stream into a collection, and traversing the elements.

So much said, for example:

Data processing prior to Java 8:

/**
* Filter out elements in the collection whose type attribute is not equal to TaskType.READING, and the rest of the collection elements are sorted in ascending order of title.
* Last output title Value of sorted set of remaining elements
*/
public class Example1_Java7 {
    public static void main(String[] args) {
        List<Task> tasks = getTasks();
        List<Task> readingTasks = new ArrayList<>();
        for (Task task : tasks) {
            if (task.getType() == TaskType.READING) {
                readingTasks.add(task);
            }
        }
        Collections.sort(readingTasks, new Comparator<Task>() {
            @Overridepublic int compare(Task t1, Task t2) {
                return t1.getTitle().length() - t2.getTitle().length();
            }
        });
        for (Task readingTask : readingTasks) {
            System.out.println(readingTask.getTitle());
        }
    }
}

java8 processing:

public class Example1_Stream {
    public static void main(String[] args) {
        List<Task> tasks = getTasks();
        List<String> readingTasks = tasks.stream()
                .filter(task -> task.getType() == TaskType.READING)
                .sorted((t1, t2) -> t1.getTitle().length() - t2.getTitle().length())
                .map(Task::getTitle)
                .collect(Collectors.toList());
        readingTasks.forEach(System.out::println);
    }
}

The output of the above two examples is the same, but java8 looks much simpler

Tags: Programming Java Database SQL

Posted on Sun, 05 Apr 2020 01:23:18 -0700 by mastermike707