Preface
In recent internship, I saw some codes of my predecessors in the company, and found that there are many places worth learning. One part of them is to use Stream stream operation for collection, which is very beautiful and convenient. So learn some Stream streams and record them here.
What is Stream
Stream is a new feature in Java 8, which greatly enhances the function of collection objects and focuses on the convenient and efficient aggregation operation of collection objects. In addition, it can cooperate with Lambda expression to make the code easier to understand. In addition, stream provides two modes of operation, serial and parallel. Parallel operation can easily write high-performance concurrent programs.
Stream is like an advanced version of Iterator. With Iterator, we can only explicitly traverse one element and perform some operations on it. With stream, we only need to specify what operations to perform on the elements contained in the collection, such as "only get the user whose gender is male", "get the last name of each user" and so on. Stream will help us to complete the implicit traversal and conversion Data.
Unlike Iterator, Iterator can only operate serially, one element at a time and then the next. Stream supports serial and parallel operations, which rely on Java 7's Fork/Join framework (JSR166y) to split tasks and speed up processing.
Stream is like a pipeline. It is unidirectional and cannot be turned back. It can only be traversed once, and then it can no longer be used.
Using a Stream stream is generally divided into three steps: 1. Get data source - > 2. Intermediate - > 3. Terminal.
Intermediate operation: a flow can have 0 or more intermediate operations, such as data conversion, filtering and other operations, one after another. These operations are lazy, and the intermediate operation has not started the real traversal.
Terminal operation: a stream can only have one terminal operation. When terminal operation is used, the result will be returned. This stream can no longer be used. Only when the terminal operates can it really start to traverse.
In a Stream, the multiple intermediate operations of a Stream are not traversed every time. The intermediate operations are lazy, and the multiple intermediate operations are finally aggregated to the terminal operations. Only one cycle of traversal is performed. It can be understood that each intermediate operation is added to the terminal operation cycle as a judgment condition to complete the data conversion of each element.
The following are the classification of some Stream operation methods:
How to create a Stream
-
array
- Arrays.stream(T array);
- stream.of(array)
- Arrays.stream(T array);
- Collection
- Collection.stream()
- Collection.parallelStream()
- BufferedReader
- java.io.BufferedReader.lines()
-
Static factory
- java.util.stream.IntStream.range()
- java.nio.file.Files.walk()
- Build yourself
- java.util.Spliterator
- Other
- Random.ints()
- BitSet.stream()
- Pattern.splitAsStream(java.lang.CharSequence)
- JarFile.stream()
Create example
//array String[] array = new String[]{"1","2","3"}; Arrays.stream(array); Stream.of(array); Stream.of(1, 2, 3); //aggregate List<String> list = Arrays.asList(array); list.stream(); list.parallelStream(); //Value, currently only three kinds of IntStream, LongStream and DoubleStream are supported IntStream.of(new int[]{1,2,3}).forEach(System.out::println); IntStream.range(1,3).forEach(System.out::println); IntStream.rangeClosed(1, 3).forEach(System.out::println);
Stream to other data structures
Stream stream = Stream.of("1","2","3"); //Array String[] array2=(String[]) stream.toArray(String[]::new); //Collection List<String> list1=(List)stream.collect(Collectors.toList()); List<String> list2=(List)stream.collect(Collectors.toCollection(ArrayList::new)); Set set=(Set)stream.collect(Collectors.toSet()); Stack stack=(Stack)stream.collect(Collectors.toCollection(Stack::new)); //String String str = stream.collect(Collectors.joining()).toString();
Classic usage
1. Take out an attribute of an element in a list as a list and filter it
List<Long> names= users.stream().filter(Objects::nonNull).map(User::getId).collect(Collectors.toList()); //perhaps List<Long> names1= users.stream().filter(Objects::nonNull).map(u->u.getId()).collect(Collectors.toList()); //Traversing list names.forEach(System.out::println);
2. Convert List to Map
//key:id value:name Map<Long, String> map = users.stream().collect(Collectors.toMap(p -> p.getId(), p -> p.getName())); //Or, the third parameter indicates that if the key keeps k1 repeatedly, k2 will be discarded. Map<Long, String> map2 = users.stream().collect(Collectors.toMap(User::getId,User::getName,(k1,k2)->k1)); //key:id value:user Map<Long, User> map3 = users.stream().collect(Collectors.toMap(p -> p.getId(), p->p)); //Traversal map, including k,v. map.values.forEach() cannot traverse Key map3.forEach((k,v)-> System.out.println("k:v="+k+":"+v));
3. Sort the List with sorted
//Descending, default is ascending List<User> list= users.stream().sorted(Comparator.comparing(User::getId).reversed()).collect(Collectors.toList()); //Traversing list list.forEach(System.out::println);
Comparator.comparing(User::getId) represents the data sorted by id.
4. Group the List into a Map
//Group by gender Map<String,List<User>> map=users.stream().collect(Collectors.groupingBy(User::getSex)); map.forEach((k,v)-> System.out.println("k:v="+k+":"+v));
5. Use map to convert upper case
List<String> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); list1.add("c"); List<String> list2 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
6. flatMap and map
//map List<String> str = Arrays.asList("a,b,c", "d,e", "f"); List<String[]> list1 = str.stream().map(s -> s.split(",")).collect(Collectors.toList()); list1.forEach(p-> System.out.print(Arrays.toString(p)+","));//[a, b, c],[d, e],[f] //flatMap List<String> list2 = str.stream().map(s -> s.split(",")).flatMap(Arrays::stream).sorted(Comparator.comparing(p->p.toString()).reversed()).collect(Collectors.toList()); System.out.println(list2);//[f, e, d, c, b, a]
The difference between flatMap and map is that flatMap transforms every element in a stream into a stream. After flatMap, we get the total set of elements in each stream. That is to say, we traverse each stream twice to extract the elements and merge them into the total set.
7. reduce
//Sum sum=11, the first parameter 1 is the initial value (seed), and the second parameter is the binary operator. 1+1+2+3+4=11 Integer sum = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum); //concat="ABCD"; String concat = Stream.of("A", "B", "C").reduce("", String::concat); //Sum. The reduce method has no initial value. The return type is Optional. You need to call the get() method to get a value. Integer sum2 = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get(); //Take the maximum value, max=2.0. Double max = Stream.of(1.0, 2.0, -1.0, 1.5).reduce(Double.MIN_VALUE, Double::max);
optional is also a new feature in Java 8. It can store null or instance. Let's talk more about it.
8. limit and skip
List<Long> ids=users.stream().map(User::getId).limit(5).skip(2).collect(Collectors.toList()); ids.forEach(System.out::println);//1-10 outputs 2 3 4
limit(5) limits only the first five, skip(2) skips the first two. Especially, if limit and skip are used together with sorted, limit and skip should be used first.
Life goes on, learning goes on. Further efforts are needed. Twenty million one hundred and ninety-one thousand two hundred and ten