Flow operation of new Java 8 features

Keywords: Programming Java Database SQL less

What is flow operation

The Java 8 API adds a new abstraction called streaming Stream, which allows you to process data in a declarative way.

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

Stream API can greatly improve the productivity of Java programmers and make them write efficient, clean and concise code.

This style regards the set of elements to be processed as a flow, which is transmitted in the pipeline and can be processed on the nodes of the pipeline, such as filtering, sorting, aggregation, etc.

The element flow is processed by intermediate operation in the pipeline, and the final operation gets the result of the previous processing.

1. Flow operation example

1.1 create entity class

public class Person {

    private String name;

    private Integer age;

    private Integer score;

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public Integer getAge() {

        return age;

    }

    public void setAge(Integer age) {

        this.age = age;

    }

    public Integer getScore() {

        return score;

    }

    public void setScore(Integer score) {

        this.score = score;

    }

    public Person() {

    }

    public Person(String name, Integer age, Integer score) {

        this.name = name;

        this.age = age;

        this.score = score;

    }

    @Override

    public String toString() {

        return "Person{" +

                "name='" + name + '\'' +

                ", age=" + age +

                ", score=" + score +

                '}';

    }

}

 

1.2 traditional object initialization method

public class Program {

    public static void main(String[] args) {

        //Using constructors to set object information

//Person xiaomign = new Person("Xiaoming", 28, 90);

        //Use getter and setter to set object information

        Person xiaoming = new Person();

        xiaoming.setName("Xiao Ming");

        xiaoming.setAge(18);

        xiaoming.setScore(90);

    }

}

1.3 initializing objects with streaming operations

1.3.1 modify entity class

public class Person {

    private String name;

    private Integer age;

    private Integer score;

    public String getName() {

        return name;

    }

    public Person setName(String name) {

        this.name = name;

        return this;

    }

    public Integer getAge() {

        return age;

    }

    public Person setAge(Integer age) {

        this.age = age;

        return this;

    }

    public Integer getScore() {

        return score;

    }

    public Person setScore(Integer score) {

        this.score = score;

        return this;

    }

    public Person() {

    }

    public Person(String name, Integer age, Integer score) {

        this.name = name;

        this.age = age;

        this.score = score;

    }

    @Override

    public String toString() {

        return "Person{" +

                "name='" + name + '\'' +

                ", age=" + age +

                ", score=" + score +

                '}';

    }

}

1.3.2 use flow operation

//Streaming operation

xiaoming.setName("Xiao Ming").setAge(20).setScore(100);

2. Flow operation of set

The streaming operation of collection is a new feature of Java 8. The streaming operation is not a data structure, and it is not responsible for any data storage. It is more like an iterator, which can get every data in the data source orderly, and can perform some operations on these data. The return value of each method of a streaming operation is the flow itself.

2.1 three steps of flow operation

2.1.1 get data source: set, array

set up data sources

public class Data {

    /**

    * data source

    */

    public static ArrayList<Person> getData() {

        ArrayList<Person> list = new ArrayList<Person>();

        list.add(new Person("Xiao Ming", 18, 100));

        list.add(new Person("Xiaoli", 19, 70));

        list.add(new Person("Xiao Wang", 22, 85));

        list.add(new Person("Xiao Zhang", 20, 90));

        list.add(new Person("Small black", 21, 95));

        return list;

    }

}

How to get the data source

public class Program {

    public static void main(String[] args) {

        // Get data source mode 1

        Stream stream = Data.getData().stream();

        // Get data source mode 2

        Stream.of(Data.getData());

 

        // Get data source mode 3

        //Data source is array

    }

}

2.1.2 data processing: filtering, sorting, mapping, etc. (intermediate operation)

Intermediate operation 1: filter

Filter data using filter custom criteria

// Intermediate operation 1: filter

// Filter is a filter. You can customize a filter condition to keep the elements in the flow that meet the condition

// Find students with scores less than 80 in the set

List<Person> list = Data.getData().stream()

    .filter(ele -> ele.getScore() < 80)

    .collect(Collectors.toList());

System.out.println(list);

 

Intermediate operation 2: distinct

Using distinct to realize de duplication

Add duplicate data to the data source

list.add(new Person("Small black", 21, 95)); //At this time, there are two small black in the list

Override hashCode() and equals() methods in entity classes

@Override

public boolean equals(Object o) {

    if (this == o) return true;

    if (o == null || getClass() != o.getClass()) return false;

    Person person = (Person) o;

    return Objects.equals(name, person.name) &&

        Objects.equals(age, person.age) &&

        Objects.equals(score, person.score);

}

@Override

public int hashCode() {

    return Objects.hash(name, age, score);

}

De duplication rules:

Determine the hashCode() of the object first

If hashCode() is the same, judge equals()

// Intermediate operation 2: distinct

// distinct: extract different elements from the collection

// De duplication rules:

// 1. First determine the hashCode()

// 2. If hashCode() is the same, judge equals()

Data.getData().stream().distinct().forEach(System.out::println);

Note: if the data of small black is the same but two copies need to be saved, you can return a random number in the hashCode() method, and the probability of the random number is the same. To ensure stability, you can change the equals() method to return false, so that two small black with the same information can be retained.

Intermediate operation 3: sorted

Use the sorted() method to sort grades in ascending order

Require entity class to implement compatible interface and override method

// Intermediate operation 3: sorted

// sorted: sorts the returned elements

// sorted(): requires the entity class to implement the compatible interface and override the method

Data.getData().stream().sorted().forEach(System.out::println);

 

Intermediate operation 4: limit

Take the first three data in the data source

// Intermediate operation 4: limit

// Limit: limit, only the data in the flow that is located by the front finger

// Take the first three data in the data source

Data.getData().stream().limit(3).forEach(System.out::println);

 

Intermediate operation 5: skip

// Intermediate operation 5: skip

// Skip: skip over

// Skip the first three elements and take the rest

Data.getData().stream().skip(3).forEach(System.out::println);

 

Intermediate operation 6: map

Element mapping, replacing elements in the stream with specified elements

Use map to replace an object with its name

// Intermediate operation 6: map

// map: element mapping, replacing the elements in the stream with the specified elements

// Replace the Person object in the stream with their name

Data.getData().stream().map(ele -> ele.getName()).forEach(System.out::println);

 

2.1.3 data integration in convection: transfer to set, quantity (final operation)

Final operation 1: collect

Convert to List

public class Program {

    public static void main(String[] args) {

        // Get data source mode 1

        Stream<Person> stream = Data.getData().stream();

        // Final operation 1: collect, used with Collectors

        // Convert elements in a collection to a List

        List<Person> list = stream.collect(Collectors.toList());

        System.out.println(list);

    }

}

Operation result

 

Convert to set

// Convert elements in a collection to a Set

Set<Person> set = stream.collect(Collectors.toSet());

System.out.println(set);

Operation result

 

Convert to map

// Convert to Map (name as key, score as value)

        // Mode 1

//        Map<String, Integer> map = stream.collect(Collectors.toMap(

//                ele -> ele.getName(),

//                ele -> ele.getScore()

//        )); 

 

        // Mode 2

        Map<String, Integer> map = stream.collect(Collectors.toMap(

                Person::getName,

                Person::getScore

        ));

Operation result

 

Final operation 2: reduce

The thought of reduce

For example, when calculating the sum of elements in an array, the sum of the first two numbers will be calculated first, and then the sum of the first two numbers and the third number will be calculated. After calculating the result, the sum of the three numbers and the fourth number will be added, and so on.

 

Calculating the sum of data in an array

// Final action 2: reduce (summarize data)

Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Optional<Integer> res = stream1.reduce((n1, n2) -> n1 + n2);

// Get the final return value

System.out.println(res.get());

Using reduce to calculate the sum of the scores in the Person object

// Calculate the sum of scores in Person

Optional<Person> res = stream.reduce(

    (n1, n2) -> new Person().setScore(n1.getScore() + n2.getScore())

);

System.out.println(res.get().getScore());

Disadvantages: the above method will generate a temporary object each time, resulting in unnecessary performance loss

Using reduce to calculate the sum of the scores in the Person object (optimization)

// Calculate the sum of scores in Person (use temporary variables to reduce performance overhead)

Person temp = new Person();

Optional<Person> res = stream.reduce(

    (n1, n2) -> temp.setScore(n1.getScore() + n2.getScore())

);

System.out.println(res.get().getScore());Final operation 3: max and min

 

Use max to find the Person with the highest score in Person

// Final operation 3: max and min

// Requirement 1: find the information of the highest achievers in the collection

Person max = stream.max(

    (ele1, ele2) -> ele1.getScore() - ele2.getScore()

).get();

System.out.println(max);

 

Use min to find the Person with the lowest score in Person

// Requirement 2: find information about the lowest achievers in the set

Person min = stream.min(

    (ele1, ele2) -> ele1.getScore() - ele2.getScore()

).get();

System.out.println(min);

 

Final operation 4: matching

Use anyMatch to see if there are people in the collection with scores higher than 80

// Judge whether students with scores greater than 80 are included in the set

boolean res1 = stream.anyMatch((ele) -> ele.getScore() > 80);

System.out.println(res1);

 

Use allMatch to see if the scores in the collection are all higher than 60

//See if all of the people in the collection are above 60

boolean res2 = stream.allMatch((ele) -> ele.getScore() > 60);

System.out.println(res2);

 

Use noneMatch to see if people in the collection don't have scores below 80

boolean res3 = stream.noneMatch((ele) -> ele.getScore() < 80);

System.out.println(res3);

 

Final operation 5: count

Use count to calculate how many pieces of data are in metadata

// Final operation 5: find how many elements are in the metadata

long count = stream.count();

System.out.println(count);

 

Final operation 6: forEach

Traversing elements in a collection using forEach

// Final operation 6: forEach

// stream.forEach(ele -> System.out.println(ele));

stream.forEach(System.out::println);

 

Final action 7: findFirst and findAny FindFirst: get the first element in the stream FindAny: get any element in the stream (not random get element) for a serial stream, the result is the same as findFirst findAny used in a parallel stream, which may be the same as or different from findFirst

// FindFirst: get the first element in the stream

// FindAny: get any element in the stream (not random)

//For a serial stream, the result is equivalent to findFirst

//findAny may or may not be used in parallel flows as findFirst

System.out.println(Data.getData().parallelStream().findFirst());

System.out.println(Data.getData().stream().findFirst());

System.out.println(Data.getData().parallelStream().findAny());

System.out.println(Data.getData().stream().findAny());

Precautions for final operation

Why is it called the final operation?

Person max = stream.max(

    (ele1, ele2) -> ele1.getScore() - ele2.getScore()

).get();

Person min = stream.min(

    (ele1, ele2) -> ele1.getScore() - ele2.getScore()

).get();

 

The error message indicates that the stream is being processed or has been closed. If it is closed and called again, the error will be reported, which is why it is called the final operation.

3. parallel flow

3.1 way to obtain parallel flow

// Parallel flow

// Two ways to get parallel flow

Data.getData().stream().parallel();

Data.getData().parallelStream();

3.2 comparison of parallel flow and serial flow

// Serial stream: 19920ms

// Parallel flow: 12204ms

long startTime = System.currentTimeMillis();

//LongStream.rangeClosed(0L, 50000000000L)

//    .reduce(Long::sum);

LongStream.rangeClosed(0L, 50000000000L)

    .parallel()

    .reduce(Long::sum);

long endTime = System.currentTimeMillis();

System.out.println(endTime - startTime);

3.3 flatMap

String[] array = {"hello", "world"};

// Need to get all characters list - > H, e, l, l, O, W, O, R, l, D

//        Arrays.stream(array)

//                .map(ele -> ele.split(""))

//                .forEach(ele -> System.out.println(ele.length));

System.out.println(Arrays.stream(array)

                  .map(ele -> ele.split(""))

                  .flatMap(Arrays::stream)

                  .collect(Collectors.toList()));

 

4.Collectors

Collectors is a tool class that provides several methods to return an implementation class object of Collector interface

4.1 maxBy

Gets the largest element in the flow through the specified rule

System.out.println(Data.getData().stream()

                .collect(Collectors.maxBy((ele1, ele2) -> ele1.getScore() - ele2.getScore())));

 

4.2 minBy

Gets the smallest element in the flow through the specified rule

System.out.println(Data.getData().stream()

                .collect(Collectors.minBy((ele1, ele2) -> ele1.getScore() - ele2.getScore())));

 

4.3 joining

Merge, the elements in the stream are spliced in the form of strings

// Spell the name in Person into a string

String res1 = Data.getData().stream()

    .map(Person::getName)

    .collect(Collectors.joining());

System.out.println(res1);

 

String res2 = Data.getData().stream()

    .map(Person::getName)

    .collect(Collectors.joining("-"));

System.out.println(res2);

 

String res3 = Data.getData().stream()

    .map(Person::getName)

    .collect(Collectors.joining("-", "{", "}"));

System.out.println(res3);

 

4.4 summingInt

Calculate the sum of int type, and map the elements in the flow to the sum of int type elements

Sum the performance of Person object

// Sum the performance of Person object

System.out.println(Data.getData().stream()

                  .collect(Collectors.summingInt(ele -> ele.getScore())));

 

4.5 averagingInt

Average int

Calculate the average of failing students

System.out.println(Data.getData().stream()

                  .filter(ele -> ele.getScore() < 60)

                  .collect(Collectors.averagingInt(Person::getScore)));

4.6 summarizingInt

Map the elements in the flow to the elements of type int to obtain the description information of these data

System.out.println(Data.getData().stream()

                  .collect(Collectors.summarizingInt(ele -> ele.getScore())));

 

 

If you want to get more learning materials, please comment on [learning] below the comment

Link: https://juejin.im/post/5e15e9fc5188253a9b1bf858

Posted by mathewvp on Thu, 16 Jan 2020 00:24:28 -0800