Playing with Stream in Java 8

Keywords: Programming Java Lambda less Linux

Playing with Stream in Java 8

By litesky

Link: http://www.jianshu.com/p/11c925cdba50

I believe you have heard about Java8 Stream, but you may not be able to use it or you are not familiar with it. This article will take you to use it from scratch, step by step, and lead you to the peak of Stream.

Operator

What are operators? Operator is a kind of data processing work, a processing program, just like the factory workers to process the products on the assembly line.

Stream operators are generally divided into two types: intermediate operator and termination operator

Middle operator

For data flow, after the intermediate operator executes the development handler, the data flow can still be passed to the next level of operators.

There are eight kinds of intermediate operators (excluding parallel and sequential operations, which do not involve data flow processing operations):

Map (mapto int, mapto long, mapto double) conversion operators, such as a - > b, are provided by default. flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) flattening operation, such as changing int[]{2,3,4} to 2,3,4, that is, from the original data to 3 data. Here, the operator of flattening to int,long,double is provided by default. limit current limiting operation, for example, I only need to use the first three of the 10 data flows. Distinct de duplication operation, de duplication of repeated elements, the underlying use of the equals method. Filter operation to filter unwanted data. peek selects operations. If you want to perform some operations on the data, such as reading, editing and modifying, etc. Skip skip operation, skipping some elements. sorted(unordered) sorting operation is used to sort elements, provided that the compatible interface is implemented, and of course, the comparer can also be customized.

Termination operator

After the intermediate processing operation, it's the termination operator's turn to play; the termination operator is used to collect or consume the data. When the data reaches the termination operation, it will not flow down, and the termination operator can only be used once.

collect collection operation collects all data. This operation is very important. The official Collectors provide a lot of Collectors. It can be said that the core of Stream is Collectors. Count the operation to count the final number of data. findFirst, findAny search operation, find the first, find any return type as Optional. The return value of whether there is a qualified element in the data flow is bool. For min and max maximum operations, you need to customize the comparator to return the maximum and minimum values in the data flow. Reduce specification operation: the value of the entire data flow is specified as a value. The bottom layer of count, min and max is to use reduce. forEach, forEachOrdered traversal operations, here is the final data consumption. toArray array operation, which converts the elements of the data stream into an array. This article only introduces Stream, not IntStream, LongStream and DoubleStream. These three streams implement some special operators, which I will introduce in the following articles. Java reply to the interview question in the official account, and send you a collection of interview details of major companies.

It's not enough to just introduce these operators after so much talk; as the saying goes, practice gives you real knowledge. So Let's go.

Code walkthrough

A series of operations of Stream must be terminated. Otherwise, the whole data Stream will not flow, that is, the processing operation will not be executed.

Map, you can see that the map operator requires that the Function of a Function be an interface instance, and the Function is to convert T type to R type.

The map operation converts the original word into the length of each single, using the length() method of String itself, which returns the type of int. Here I directly use lambda expression, about lambda expression please readers to understand it.

public class Main {

    public static void main(String[] args) {
        Stream.of("apple","banana","orange","waltermaleon","grape")
                .map(e->e.length()) //Length of converted word int
                .forEach(e->System.out.println(e)); //output
    }
}

Of course, it is also possible to use member function references here. For the convenience of readers, lambda expressions will be used instead of function references in subsequent examples.

public class Main {

    public static void main(String[] args) {
         Stream.of("apple","banana","orange","waltermaleon","grape")
                .map(String::length) //Length of converted word int
                .forEach(System.out::println);
    }
}

The results are as follows:

mapToInt converts the elements in the data stream to int, which limits the type of the conversion int. the resulting stream is IntStream, and the result can only be converted to int.

public class Main {

    public static void main(String[] args) {
         Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .mapToInt(e -> e.length()) //Convert to int
                .forEach(e -> System.out.println(e));
    }
}

mapToInt is shown in the figure:

mapToLong, mapToDouble are similar to mapToInt

public class Main {

    public static void main(String[] args) {
         Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .mapToLong(e -> e.length()) //Convert to long, int in essence, but there is automatic conversion of type
                .forEach(e -> System.out.println(e));
    }
}

mapToLong is shown in the figure:

public class Main {

    public static void main(String[] args) {
         Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .mapToDouble(e -> e.length()) //Convert to Double, automatic type conversion to Double
                .forEach(e -> System.out.println(e));
    }
}

mapToDouble is shown in the figure:

The function of flatmap is to flatten and flatten the elements, reorganize the flattened elements into streams, and merge these streams into one Stream in series

public class Main {

    public static void main(String[] args) {
        Stream.of("a-b-c-d","e-f-i-g-h")
                .flatMap(e->Stream.of(e.split("-")))
                .forEach(e->System.out.println(e));

    }
}

flatmap is shown as follows:

flatmapToInt, flatmapToLong, flatmapToDouble and flatMap are all similar, but the type is limited, so there are no examples here.

Limit limit limit the number of elements. Just pass in the long type to indicate the maximum number of limit elements

public class Main {

    public static void main(String[] args) {
        Stream.of(1,2,3,4,5,6)
                .limit(3) //Limit three
                .forEach(e->System.out.println(e)); //Output the first three 1, 2, 3
    }
}

limit is shown in the figure:

public class Main {

    public static void main(String[] args) {

        Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1)
                .distinct() //duplicate removal
                .forEach(e->System.out.println(e));

    }
}

See the figure below:

Filter filters some elements. Those that do not meet the filter criteria will not be able to enter the downstream of the flow

public class Main {

    public static void main(String[] args) {
        Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1)
                .filter(e->e>=5) //Filter less than 5
                .forEach(e->System.out.println(e));
    }
}

The filter is shown in the figure:

peek selection, to select elements, can be understood as early consumption

public class Main {

    public static void main(String[] args) {

        User w = new User("w",10);
        User x = new User("x",11);
        User y = new User("y",12);

        Stream.of(w,x,y)
                .peek(e->{e.setName(e.getAge()+e.getName());}) //Reset name to age + name
                .forEach(e->System.out.println(e.toString()));

    }

    static class User {

        private String name;

        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

}

peek is as follows:

Skip skip element

public class Main {

    public static void main(String[] args) {
        Stream.of(1,2,3,4,5,6,7,8,9)
                .skip(4) //Skip the first four
                .forEach(e->System.out.println(e)); //The output should be only 5, 6, 7, 8, 9
    }
}

skip is shown in the figure:

The sorted sorting bottom layer depends on the implementation of compatible, and can also provide a custom comparer Here Integer implements comparator

public class Main {

    public static void main(String[] args) {
        Stream.of(2,1,3,6,4,9,6,8,0)
                .sorted()
                .forEach(e->System.out.println(e));
    }
}

The sorted default comparator is shown in the figure:

The User can implement the Comparable interface

public class Main {

    public static void main(String[] args) {

        User x = new User("x",11);
        User y = new User("y",12);
        User w = new User("w",10);

        Stream.of(w,x,y)
                .sorted((e1,e2)->e1.age>e2.age?1:e1.age==e2.age?0:-1)
                .forEach(e->System.out.println(e.toString()));

    }

    static class User {

        private String name;

        private int age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

}

As shown in the figure:

collect. The final data flow can be collected into the List, Set, Map and other containers by using the collector provided by the system. Here I use collect to collect elements into a set

public class Main {

    public static void main(String[] args) {
        Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .collect(Collectors.toSet()) //set container
                .forEach(e -> System.out.println(e));
    }
}

Eh? , doesn't it mean that the termination operator can only be used once? Why is forEach called here? forEach is not only an operator in Stream, but also a syntactic sugar in various collections. Please try it. Java reply to the interview question in the official account, and send you a collection of interview details of major companies.

public class Main {

    public static void main(String[] args) {

        Set<String> stringSet = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .collect(Collectors.toSet()); //The result of collection is set
        stringSet.forEach(e->System.out.println(e)); set Grammar sugar of forEach
}

The results are as follows:

count counts the number of elements in the data stream, and returns the long type

public class Main {

    public static void main(String[] args) {

        long count = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .count();

        System.out.println(count);
    }
}

count is as shown in the figure:

findFirst gets the first element in the stream The first element apple is found here

public class FindFirst {

    public static void main(String[] args) {
        Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .findFirst();
        stringOptional.ifPresent(e->System.out.println(e));
    }
}

The findFirst result is shown in the figure below:

findAny gets any element in the stream

public class FindAny {

    public static void main(String[] args) {
        Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
                .parallel()
                .findAny(); //In parallel flow, the result may be the same or different each time
        stringOptional.ifPresent(e->System.out.println(e));
    }
}

findAny uses results in parallel streams:

Output orange

Output banana

None of the elements in the noneMatch data stream matches the condition The function here is to judge that none of the data streams has the same element as aa, but there is aa in the stream, so the final result should be false

public class NoneMatch {

    public static void main(String[] args) {
        boolean result = Stream.of("aa","bb","cc","aa")
                .noneMatch(e->e.equals("aa"));
        System.out.println(result);
    }
}

noneMatch is shown in the figure:

One of allMatch and anyMatch is full match, the other is any match is similar to noneMatch, so there is no example here.

min the smallest one, incoming comparator, or not (if the data flow is empty)

public class Main {

    public static void main(String[] args) {

        Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1)
                .min((e1,e2)->e1.compareTo(e2));

        integerOptional.ifPresent(e->System.out.println(e));

    }

min as shown in the figure:

The largest of the max elements needs to be passed in the comparator, or it may not (when the stream is Empty)

public class Main {

    public static void main(String[] args) {

        Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1)
                .max((e1,e2)->e1.compareTo(e2));

        integerOptional.ifPresent(e->System.out.println(e));

    }
}

max is shown in the figure:

reduce is a specification operation. All elements are reduced to one, such as summing and multiplying all elements. Here an addition is implemented, specifying the initialization value

public class Main {
    public static void main(String[] args) {

        int sum = Stream.of(0,9,8,4,5,6,-1)
              .reduce(0,(e1,e2)->e1+e2);
        System.out.println(sum);
    }
}

reduce is shown in the figure:

forEach forEach has seen it before, iterating over each data

forEachOrdered is suitable for iteration under the condition of parallel flow, and can ensure the order of iteration Here, the numbers are output in parallel

public class ForEachOrdered {
    public static void main(String[] args) {
        Stream.of(0,2,6,5,4,9,8,-1)
                .parallel()
                .forEachOrdered(e->{
                    System.out.println(Thread.currentThread().getName()+": "+e);});
    }
}

forEachOrdered is shown in the figure:

toArray can be converted into an array to provide a custom array generator

public class ToArray {
    public static void main(String[] args) {
        Object[] objects=Stream.of(0,2,6,5,4,9,8,-1)
                .toArray();

        for (int i = 0; i < objects.length; i++) {
            System.out.println(objects[i]);
        }
    }
}

toArray is shown as follows:

summary

Java8 Stream brings you to realize that if you can type every example in my article, you can master the preliminary usage of these operators.

Wechat search: Java show replied to the "manual" to get a copy of Java core interview manual + linux practical command manual.

Posted by michibk on Sat, 27 Jun 2020 19:14:03 -0700