Java8 Stream detailed usage introduction

1. Stream overview

Stream stream is a new member of JDK8, which allows data collection to be processed in a declarative manner. Stream stream can be regarded as an advanced iterator for traversing data collection . Stream is the key abstraction concept for processing collections in Java8. It can specify the operations you want to perform on collections, and can perform very complex operations such as searching/filtering/filtering, sorting, aggregation, and mapping data. The Stream API provides an efficient and easy-to-use way of processing data.

1.1. Definition of flow

A sequence of elements produced from a source that supports data processing operations. Data sources can be collections, arrays or IO resources.

1.2, stream and collection

stream Collection
The main purpose Mainly used to describe calculations on data Primarily for storing and accessing data
calculating time Calculated only when needed Each element is computed first
traversal mode internal iteration external iteration

1.3. Characteristics of streams

  • It is not a data structure and does not save data. The purpose of stream is to process data.
  • stream does not change the data source, usually a new collection or a value is produced.
  • Lazy evaluation, during the middle processing of the stream, the operation is only recorded and not executed immediately, and the actual calculation will not be performed until the termination operation is executed.

1.4, Creation of Stream

1. Create an empty stream through Stream.empty()

Stream<String> streamEmpty = Stream.empty();

2. Create a stream with a collection through the java.util.Collection.stream() method

List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();

3. Use the java.util.Arrays.stream(T[]array) method to create a stream with an array

int[] array={
    
    1,3,5,6,8};
IntStream stream = Arrays.stream(array);

4. Created by the constructor Stream.builder()

When using a builder, you should additionally specify the desired type in the right part of the statement, otherwise the build() method will create an instance of Stream

Stream<String> streamBuilder = 
	Stream.<String>builder().add("a").add("b").add("c").build();

5. Use the static methods of Stream: of(), iterate(), generate()

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);

6. Created by File

The Java NIO class Files allows to generate a Stream of text files via the lines() method. Each line of text becomes an element of the stream:

Path path = Paths.get("C:\\file.txt");
Stream<String> streamOfFile = Files.lines(path);
Stream<String> streamWithCharset = Files.lines(path, Charset.forName("UTF-8"));

1.5, Stream operation classification

insert image description here

Stream operations are divided into two types:

  • Intermediate operations return a new stream each time, and there can be multiple.

    • Stateless: means that the processing of elements is not affected by previous elements;
    • Stateful: It means that the operation can only continue after all the elements are obtained.
  • Terminal operation, each stream can only perform one terminal operation, and the stream cannot be used again after the terminal operation is completed. Terminal operations result in a new collection or value.

    • Non-short-circuit operation: means that all elements must be processed to get the final result;
    • Short-circuit operation: It means that the final result can be obtained when certain elements meet the conditions, such as A || B. As long as A is true, there is no need to judge the result of B.

insert image description here

2. Use of Stream API

2.1 Intermediate operations

2.1.1, filter() filtering

A filter filters all elements of a stream according to the given predicate and returns a new stream.
insert image description here
data preparation:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Fruit {
    
    
    //id
    private Integer id;
    //名称
    private String name;
    //颜色
    private String color;
    //数量
    private Integer num;
    //重量
    private Double weight;
}

List<Fruit> fruitList = new ArrayList<>();
fruitList.add(new Fruit(1, "apple", "green", 4, 300.0));
fruitList.add(new Fruit(2, "apple", "red", 14, 325.0));
fruitList.add(new Fruit(3, "apple", "yellow", 27, 450.0));
fruitList.add(new Fruit(4, "orange", "yellow", 10, 100.0));
fruitList.add(new Fruit(5, "banana", "yellow", 22, 250.0));
//1.查找重量大于400的苹果 filter
fruitList.stream().filter(p -> p.getName().equals("apple"))
	.filter(p -> p.getWeight() > 400.0)
	.forEach(System.out::println);
//结果输出
Fruit(id=3, name=apple, color=yellow, num=27, weight=450.0)

2.1.2, map and flatMap mapping

map: Use a given conversion function to convert the elements contained in the Stream, and the newly generated Stream only contains the converted elements, one-to-one mapping
insert image description here

//2.将每种颜色苹果的数量增加5 map
fruitList.stream().filter(p -> p.getName().equals("apple"))
	.map(m -> m.getNum() + 5)
	.forEach(System.out::println);
//输出结果,新生成的Stream只包含苹果的数量
9
19
32

flatMap: Use a given conversion function to convert the elements contained in the Stream, and the newly generated Stream only contains the converted elements, one-to-many mapping
insert image description here

//3.输出各种颜色苹果的数量 flatMap
fruitList.stream().filter(p -> p.getName().equals("apple"))
	.flatMap(m -> Stream.of(m.getColor() + ": " + m.getNum()))
	.forEach(System.out::println);
//输出结果
green: 4
red: 14
yellow: 27

2.1.3, sorted() sorting

The sorting of the Stream is done through sorted, which is stronger than the sorting of the array in that you can first perform various map, filter, limit, skip or even distinct on the Stream to reduce the number of elements before sorting, which can help the program to be significantly shortened execution time.

//4.按重量由大到小对苹果进行排序 sorted倒序排
fruitList.stream().filter(p -> p.getName().equals("apple"))
	.sorted(Comparator.comparing(Fruit::getWeight).reversed())
	.forEach(System.out::println);
//输出结果
Fruit(id=3, name=apple, color=yellow, num=27, weight=450.0)
Fruit(id=2, name=apple, color=red, num=14, weight=325.0)
Fruit(id=1, name=apple, color=green, num=4, weight=300.0)

2.1.4, distinct() deduplication

distinct() deduplicates the same elements in the stream

List<String> typeList = fruitList.stream().map(Fruit::getName).distinct().collect(Collectors.toList());
//["apple","orange","banana"]

2.1.5, concat() merge

concat() merges two streams

String[] arr1 = {
    
     "a", "b", "c", "d" };
String[] arr2 = {
    
     "a", "d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
List<String> newList = Stream.concat(stream1, stream2).collect(Collectors.toList());
//流合并:[a, b, c, d, a, d, e, f, g]

2.1.6, limit() limit

limit() limits the first n data obtained from the stream

List<Integer> collect = Stream.iterate(1, x -> x + 1)
	.limit(10).collect(Collectors.toList());
//limit:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

2.1.7, skip() skip

skip() skips the first n data

List<Integer> collect2 = Stream.iterate(1, x -> x + 1)
	.skip(5).limit(5).collect(Collectors.toList());
//skip:[6, 7, 8, 9, 10]

2.1.8, boxed() boxing

Wrap primitive data types into reference types

//int[]转List
int[] decimals = {
    
    1, 2, 3, 4, 5};
List<Integer> integers = Arrays.stream(decimals).boxed().collect(Collectors.toList());

2.2 Termination of operations

2.2.1, forEach() traversal

//5.forEach遍历
fruitList.stream().forEach(System.out::println);

2.2.2, collect() collection

The collect() method is used to collect elements from steam and store them in a collection.

//6.筛选出颜色为黄色的水果 collect收集
fruitList.stream().filter(f -> f.getColor().equals("yellow"))
	.collect(Collectors.toList())
	.forEach(System.out::println);
//输出结果
Fruit(id=3, name=apple, color=yellow, num=27, weight=450.0)
Fruit(id=4, name=orange, color=yellow, num=10, weight=100.0)
Fruit(id=5, name=banana, color=yellow, num=22, weight=250.0)

2.2.2.1, partitioningBy/groupingBy partition/group

partitioningBy partition: Divide the stream into two Maps according to the conditions, for example, whether the weight is higher than 300g is divided into two parts.

groupingBy grouping: Divide the collection into multiple Maps, such as grouping fruits by type. There are single-level groupings and multi-level groupings.

insert image description here

//8.分组
//按重量是否高于300g分组 partitioningBy分区
Map<Boolean, List<Fruit>> collect = fruitList.stream().collect(Collectors.partitioningBy(p -> p.getWeight() > 300.0));
System.out.println("按重量是否高于300g分组:" + collect);
//按水果类型分组
Map<String, List<Fruit>> collect1 = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName));
System.out.println("按水果类型分组:" + collect1);
//按水果类型、颜色分组
Map<String, Map<String, List<Fruit>>> collect2 =
        fruitList.stream().collect(Collectors.groupingBy(Fruit::getName, Collectors.groupingBy(Fruit::getColor)));
System.out.println("按水果类型、颜色分组:" + collect2);

2.2.2.2, counting counting

You can use the count() aggregate function instead

2.2.2.3, averagingDouble average value

Double avgWeight = fruitList.stream().collect(Collectors.averagingDouble(Fruit::getWeight));
System.out.println("平均重量 = " + avgWeight);  //平均重量 = 285.0

2.2.2.4, maxBy minBy maximum value

You can use max(), min() aggregation functions instead

2.2.2.5, summarizingDouble statistics

DoubleSummaryStatistics statistics = fruitList.stream().collect(Collectors.summarizingDouble(Fruit::getWeight));
//重量统计 = DoubleSummaryStatistics{count=5, sum=1425.000000, min=100.000000, average=285.000000, max=450.000000}
System.out.println("重量统计 = " + statistics);

2.2.2.6, joining connection

Joining can connect the elements in the stream into a string with a specific connector (if not, connect directly).

String join = fruitList.stream().map(Fruit::getName).collect(Collectors.joining(","));
System.out.println("join = " + join);   //join = apple,apple,apple,orange,banana

2.2.2.7, toList, toSet, toMap collection conversion

//1.将不同水果种类转为list toList
List<String> typeList = fruitList.stream()
	.map(Fruit::getName).distinct()
	.collect(Collectors.toList());
//["apple","orange","banana"]

//2.将不同水果种类转为set toSet
Set<String> typeSet = fruitList.stream()
	.map(Fruit::getName)
	.collect(Collectors.toSet());
//["orange","banana","apple"]

//3.输出各种颜色苹果的数量 toMap
Map<String, Integer> appleMap = fruitList.stream()
	.filter(p -> p.getName().equals("apple"))
	.collect(Collectors.toMap(Fruit::getColor, Fruit::getNum));
//{"red":14,"green":4,"yellow":27}

2.2.3, match() match

Stream has three match methods:

  • allMatch: all elements in the Stream match the passed predicate, return true
  • anyMatch: As long as there is one element in the Stream that matches the passed predicate, return true
  • noneMatch: None of the elements in the Stream match the incoming predicate, return true
//7.匹配match
//anyMatch 任意一个匹配
fruitList.stream().anyMatch(p->p.getColor().contains("green")); //true
//noneMatch 全部不匹配
fruitList.stream().noneMatch(p->p.getColor().contains("green")); //false
//allMatch 全部匹配
fruitList.stream().allMatch(p->p.getColor().contains("green")); //false

2.2.4, count() max() sum() aggregation

// 8.聚合
//计算水果总数 sum
int sum = fruitList.stream().mapToInt(Fruit::getNum).sum();
System.out.println("sum = " + sum); //sum = 77
//计算水果种类数量 count
long count = fruitList.stream().map(Fruit::getName).distinct().count();
System.out.println("水果种类数量 = " + count);    //水果种类数量 = 3
//计算不同类型的水果数量 先分组再求和
Map<String, Integer> tSum = fruitList.stream().collect(Collectors.groupingBy(Fruit::getName, Collectors.summingInt(Fruit::getNum)));
System.out.println("tSum = " + tSum);   //tSum = {banana=22, orange=10, apple=45}
//最大重量 max
Optional<Fruit> max = fruitList.stream().max(Comparator.comparing(Fruit::getWeight));
System.out.println("最大重量 = " + max);    //最大重量 = Optional[Fruit(id=3, name=apple, color=yellow, num=27, weight=450.0)]

2.2.5, reduce() protocol

Reduction, also known as reduction, as the name suggests, is to reduce a stream into a value, which can realize the operations of summation, multiplication and maximum value of sets.
insert image description here

List<Integer> list = Arrays.asList(1, 2, 3, 4);
//求和
Optional<Integer> reduce = list.stream().reduce((x, y) -> x + y);
System.out.println("求和:" + reduce.get()); //10
//求积
Optional<Integer> reduce2 = list.stream().reduce((x, y) -> x * y);
System.out.println("求积:" + reduce2.get());	//24
//求最大值
Optional<Integer> reduce3 = list.stream().reduce((x, y) -> x > y ? x : y);
System.out.println("求最大值:" + reduce3.get());	//4

//计算水果总数
Optional<Integer> sum = fruitList.stream().map(Fruit::getNum).reduce(Integer::sum);
System.out.println("sum = " + sum.get()); //sum = 77
//计算最大重量
Optional<Double> maxWeight = fruitList.stream().map(Fruit::getWeight).reduce(Double::max);
System.out.println("maxWeight = " + maxWeight.get());   //maxWeight = 450.0

Reference article: https://www.dandelioncloud.cn/article/details/1468718846331953154

Guess you like

Origin blog.csdn.net/weixin_45698637/article/details/128469255