Don't think that Stream readability is not high anymore!

Seven or eight years have passed since Java 8 was released, and Java 14 has just been released. The functional programming and the new Stream stream API in Java 8 are still controversial.

If you don't use Stream stream, when you see Stream operation, you must have made a scornful sound to it and said in your heart, "what's this all about?".

If you are keen to use Stream stream, you must be told by others that it is not readable, or even required to use for loop operation when coding review, or even written into the cases in the company's irregular coding.

This article will tell you, don't simply think that Stream readability is not high anymore!

I'll illustrate the data around the following examples.

Here are some data of students' course scores, including student number, name, subject and score. A student union contains data of multiple different subjects.

ID Student ID Full name Subject achievement
1 20200001 Kevin Chinese 90
2 20200002 Zhang San Chinese 91
3 20200001 Kevin Mathematics 99
4 20200003 Li Si Chinese 76
5 20200003 Li Si Mathematics 71
6 20200001 Kevin English? 68
7 20200002 Zhang San Mathematics 88
8 20200003 Zhang San English? 87
9 20200002 Li Si English? 60

Scenario 1: by student number, how many students are there in total?

The data can be de duplicated by student ID. if you don't use Stream and the third-party framework, you should be able to think of the feature that the key key of Map can't be repeated to cycle through the data, and finally calculate the number of keys in Map.

/**
 * List The element in the list is an object type. For is used to recycle the key value of Map, not to duplicate it through the student number field in the object, and calculate how many students there are
 * @param students Student information
 */
private void calcStudentCount(List<Student> students) {
    Map<Long, Student> map = new HashMap<>();
    for (Student student : students) {
        map.put(student.getStudentNumber(), student);
    }
  int count = map.keySet().size();
  System.out.println("List The elements in the list are object types, using the For Recycling Map Of key The value is not repeated through the student number field in the object to calculate the number of students:" + count);
}

You may think it's simple and clear, but I want to tell you, it's wrong! In addition to the method name calcStudentCount, the redundant for loop template code cannot convey the intention of the programmer smoothly. The programmer must read the whole loop body to understand.

Next, we will use Stream to convey the intention of the programmer accurately.

The distinct method in Stream indicates de duplication, which is the same as the distinct method in MySQL. In Stream, distinct de duplication is to remove duplicate elements through hashCode() and equals() methods in Stream elements. As shown below, String type elements in List are de duplicated through distinct.

private void useSimpleDistinct() {
    List<String> repeat = new ArrayList<>();
    repeat.add("A");
    repeat.add("B");
    repeat.add("C");
    repeat.add("A");
    repeat.add("C");
    
    List<String> notRepeating = repeat.stream().distinct().collect(Collectors.toList());
    System.out.println("List The elements in the list are simple data types:" + notRepeating.size());
}

After the distinct method is called, the collect method is called for the final calculation to make it a new List type.

But in our example, the element in the List is not a normal data type, but an object, so we can't simply de duplicate it, but call the map method in the Stream first.

/**
 * List The elements in the list are object types. Use Stream to use HashMap to de duplicate the student number field in the object and calculate how many students there are
 * @param students Student information
 */
private void useStreamByHashMap(List<Student> students) {
    long count = students.stream().map(Student::getStudentNumber).distinct().count();
    System.out.println("List The elements in the list are object types, using the Stream utilize Map The number of students is calculated by de duplication of student number field in the object:" + count);
}

The map method in Stream can't simply correspond to the map structure in Java. To be exact, the map operation in Stream should be understood as a verb, meaning classification. Since it is a classification, it will turn the elements belonging to the same type into a class, and the students with the same student number naturally belong to a class, so use map(Student::getStudentNumber) to classify the students with the same student number into a class. After regenerating a flow through the map method, the hashCode() and equals() comparison of elements in the distinct intermediate operation flow are used to remove duplicate elements.

In addition, it should be noted that the use of Stream is often accompanied by the Lambda operation. Lambda is not the focus of this chapter. In this example, when using the map operation, the "method reference" - Student::getStudentNumber in the Lambda operation is used. The syntax format is "ClassName::methodName", and the complete syntax is "student - > Student. Getstudentnumber() ", which means it will be called only when it is needed. Here, it represents to classify by calling the getstudentnumber method in the student object.

Scenario 2: how many students are there by student number + name?

The traditional way is still to use the feature of key key + for loop in Map data structure:

/**
 * List The element in the list is the object type. For is used to recycle the key value of Map without repetition. The student number + name field in the object is used to de duplicate and calculate the number of students
 * @param students Student information
 */
private void useForByMap(List<Student> students) {
    Map<String, Student> map = new HashMap<>();
    for (Student student : students) {
      map.put(student.getStudentNumber() + student.getStudentName(), student);
    }
    int count = map.keySet().size();
    System.out.println("List The elements in the list are object types, using the For Recycling Map Of key Value does not pass the student number in the object repeatedly+The name field is de duplicated to calculate the number of students:" + count);

}

If the Stream stream change point is just a Lambda expression in the map operation:

/**
 * List The elements in the list are object types. Use Stream to use HashMap to de duplicate the student number + name field in the object and calculate how many students there are
 * @param students Student information
 */
private void useStreamByHashMap(List<Student> students) {
    long count = students.stream().map(student -> (student.getStudentNumber() + student.getStudentName())).distinct().count();
    System.out.println("List The elements in the list are object types, using the Stream utilize Map Pass student ID in object+The name field is de duplicated to calculate the number of students:" + count);
}

As mentioned earlier, when using map, you can use "method reference" in Lambda expression if you only need to call one method, but you need to call two methods here, so you have to use the full syntax of Lambda expression "student - > (student. Getstudentnumber() + student. Getstudentname())".

This scene is mainly familiar with Lambda expressions.

Scenario 3: group students by student number, for example: Map < long, list >, key = student number, value = student achievement information

In the traditional way, you can still use Map to realize grouping through for loop:

/**
 * Classification by for loop with Map
 * @param students Student information
 */
private Map<Long, List<Student>> useFor(List<Student> students) {
    Map<Long, List<Student>> map = new HashMap<>();
    for (Student student : students) {
        List<Student> list = map.get(student.getStudentNumber());
        if (list == null) {
            list = new ArrayList<>();
            map.put(student.getStudentNumber(), list);
        }
        list.add(student);
    }
    return map;
}

This implementation is more complex than scenario I, and is full of a large number of boilerplate code. Programmers also need to read for loop line by line to understand the meaning. Is this code really readable?

See how Stream solves this problem:

/**
 * Group operations by group
 * @param students Student information
 * @return Student information, key = student number, value = student information
 */
private Map<Long, List<Student>> useStreamByGroup(List<Student> students) {
    Map<Long, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getStudentNumber));
    return map;
}

One line of code can be grouped. Isn't this code readable?

Scenario 4: filter the data with a score lower than 70 points. The meaning of "filter" here is to exclude the data with a score lower than 70 points

Traditional for loop template code, you can add if judgment directly into the loop body without thinking:

/**
 * Filter through for loop
 * @param  students Student data
 * @return Filtered student data
 */
public List<Student> useFor(List<Student> students) {
    List<Student> filterStudents = new ArrayList<>();
    for (Student student : students) {
        if (student.getScore().compareTo(70.0) > 0) {
            filterStudents.add(student);
        }
    }
    return filterStudents;
}

When using Stream stream, you need to use the experience operation filter.

/**
 * Filter operation through Stream's filter
 * @param students Student data
 * @return Filtered student data
 */
public List<Student> useStream(List<Student> students) {
    List<Student> filter = students.stream().filter(student -> student.getScore().compareTo(70.0) > 0).collect(Collectors.toList());
    return filter;
}

If the Lambda expression in the filter returns true, it will be included in the result. If it returns false, it will be excluded.

Do you really think that the readability of Stream is not high?

Pay attention to the official account (CoderBuff) reply to "stream" to get the full version of Java8 Stream encoding real battle PDF.

This is a CoderBuff that can give programmers buff official account.

Tags: Java Lambda Programming MySQL

Posted on Sun, 22 Mar 2020 09:22:13 -0700 by mikesch