Java Stream流

目录

1 基本概念

2 创建Stream流

2.1 单列集合创建

2.2 数组创建

2.3 双列集合创建

2.4 文件创建

3 Stream中间操作

3.1 filter

3.2 map

3.3 distinct

3.4 sorted

3.5 flatMap

3.6 limit

3.7 skip

3.8 peek

4 Stream终结操作

4.1 forEach

4.2 collect

4.3 reduce

4.4 count

4.5 max&min

5 终结操作-查找与匹配

5.1 anyMatch

5.2 allMatch

5.3 noneMatch

5.4 findAny

5.5 findFirst

6 并行流parallelStream

6.1 基本概念

6.2 创建并行流

6.2.1 从集合创建

6.2.2 从数组创建

6.2.3 从值创建

6.3 并行流的操作

6.3.1 并行求和

6.3.2 并行过滤和收集

6.3.3 并行查找

6.4 注意事项


Java 8 引入了 Stream API,这是一个用于处理集合数据的强大工具。Stream API 提供了一系列高级功能,如过滤、映射、归约、查找等,使得处理集合数据变得更加简洁和高效。下面是对 Stream API 的详细介绍,包括其基本概念、常用操作和示例。

1 基本概念

  • Stream:表示一组数据的序列,支持顺序和并行操作。
  • Source:流的来源,可以是集合、数组、文件、I/O 等。
  • Intermediate Operations:中间操作,返回一个新的流,可以链式调用多个中间操作。
  • Terminal Operations:终端操作,执行流的计算并返回结果,终止流的操作链。

2 创建Stream流

2.1 单列集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
2.2 数组创建
String[] array = {"a", "b", "c"};
// Arrays.stream
Stream<String> stream = Arrays.stream(array);
// Stream.of
Stream<String> stream2 = Stream.of(array);
2.3 双列集合创建
Map<String, Integer> map = new HashMap<>();
map.put("小黑", 17);
map.put("小白", 16);
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
entrySet.stream().filter(s -> s.getValue() > 16).forEach(s -> System.out.println(s.getKey() + "===" + s.getValue()));
2.4 文件创建
try (Stream<String> lines = Files.lines(Paths.get("file.txt"), StandardCharsets.UTF_8)) {
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}

3 Stream中间操作

3.1 filter
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream().filter(n -> n > 2).collect(Collectors.toList());
System.out.println(evenNumbers); // 输出[3, 4, 5]

 过滤流中的元素,只保留满足条件的元素。

3.2 map
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> lengths = words.stream().map(String::length).collect(Collectors.toList());
System.out.println(lengths); // 输出[5, 6, 6],返回字符串长度

将流中的每个元素转换为另一种形式。 

3.3 distinct
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> uniqueNumbers = numbers.stream().distinct().collect(Collectors.toList());
System.out.println(uniqueNumbers); // 输出[1, 2, 3, 4, 5]

去重,保留唯一元素。 以下是对象中根据某属性去重的例子:

private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}
authors.stream().filter(distinctByKey(s -> s.getName())).forEach(s -> System.out.println(s.toString()));
3.4 sorted
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);
List<Integer> sortedNumbers = numbers.stream().sorted().collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]

排序,默认自然排序。 如果是根据对象中某属性排序,可以参照如下:

// 根据Book对象中的createTime属性进行降序排列
.sorted(Comparator.comparing(Book::getCreateTime).reversed())
3.5 flatMap
List<List<Integer>> lists = Arrays.asList(
                Arrays.asList(1, 2),
                Arrays.asList(3, 4)
        );
List<Integer> flatList = lists.stream().flatMap(List::stream).collect(Collectors.toList());
        System.out.println(flatList); // 输出[1, 2, 3, 4]

将流中的每个元素转换为一个流,然后将所有流扁平化为一个流。 

3.6 limit
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> limitedList = numbers.stream().limit(5).collect(Collectors.toList());
System.out.println(limitedList); // 结果: [1, 2, 3, 4, 5]

返回一个最多包含maxSize个元素的流,如果流中的元素少于maxSize,则返回所有元素,如果大于maxSize,超出部分将会被舍弃。

3.7 skip
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> skippedList = numbers.stream().skip(5).collect(Collectors.toList());
System.out.println(skippedList); // 结果: [6, 7, 8, 9, 10]

返回一个跳过前 n 个元素的流,如果流中的元素少于 n,则返回一个空流。

3.8 peek
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.stream().peek(System.out::println).filter(n -> n % 2 == 0).collect(Collectors.toList());

用于调试,打印流中的每个元素。

4 Stream终结操作

4.1 forEach
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.stream().forEach(System.out::println);

 遍历流中的每个元素。

4.2 collect
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<String> result = words.stream().filter(w -> w.startsWith("a")).collect(Collectors.toList());

将流中的元素收集到一个集合中。

4.3 reduce
// 方式一
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().reduce(Integer::sum);
sum.ifPresent(System.out::println); // 输出:15

// 方式二,提供一个初始值
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(2, Integer::sum);
System.out.println(sum); // 输出:17

归并,对流中的数据按照你指定的计算方式计算出一个结果。

4.4 count
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 9);
long count = numbers.stream().count();
System.out.println(count); // 输出:6

计算流中元素的数量。

4.5 max&min
List<Integer> numbers1 = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = numbers1.stream().max(Integer::compare);
max.ifPresent(System.out::println); // 输出:5

List<Integer> numbers2 = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = numbers2.stream().min(Integer::compare);
min.ifPresent(System.out::println); // 输出:1

max:返回流中最大值的元素。

min:返回流中最小值的元素。

5 终结操作-查找与匹配

5.1 anyMatch
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
System.out.println(anyEven); // 输出:true

检查流中是否有任何一个元素满足条件。

5.2 allMatch
List<Integer> numbers = Arrays.asList(2, 4, 6, 8);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
System.out.println(allEven); // 输出:true

检查流中所有元素是否都满足条件。

5.3 noneMatch
List<Integer> numbers = Arrays.asList(1, 3, 5, 7);
boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0);
System.out.println(noneEven); // 输出:true

检查流中没有任何元素满足条件。

5.4 findAny
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> any = numbers.stream().findAny();
any.ifPresent(System.out::println); // 输出:1

返回流中的任意一个元素(无法保证是流中第一个元素)。

5.5 findFirst
List<Integer> numbers = Arrays.asList(5, 4, 3, 2, 1);
Optional<Integer> first = numbers.stream().findFirst();
first.ifPresent(System.out::println); // 输出:5

返回流中的第一个元素。

6 并行流parallelStream

6.1 基本概念

parallelStream 是 Java 8 引入的 Stream API 的一个重要特性,它允许你以并行方式处理集合数据。并行流可以利用多核处理器的优势,加速数据处理过程。与普通的 Stream 不同,parallelStream 会在多个线程上并行处理数据,从而提高性能。需要注意的是,parallelStream() 会打乱流的顺序,也就是返回的序列顺序不一定是输入的序列顺序。

  • 并行流:并行流将数据源分成多个子部分,每个子部分在不同的线程上独立处理,最后将结果合并。
  • 并行度:并行流的并行度取决于系统的可用处理器核心数。默认情况下,Java 使用 ForkJoinPool.commonPool() 作为并行流的工作线程池。
6.2 创建并行流
6.2.1 从集合创建
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
Stream<String> parallelStream = list.parallelStream();
6.2.2 从数组创建
String[] array = {"a", "b", "c", "d", "e"};
Stream<String> parallelStream = Arrays.stream(array).parallel();
6.2.3 从值创建
Stream<String> parallelStream = Stream.of("a", "b", "c", "d", "e").parallel();
6.3 并行流的操作

并行流支持与普通流相同的操作,包括中间操作和终端操作。但是,由于并行流的并行处理特性,某些操作的行为可能会有所不同。以下为部分操作示例:

6.3.1 并行求和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream().reduce(0, Integer::sum);
System.out.println(sum); // 输出: 55
6.3.2 并行过滤和收集
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = numbers.parallelStream().filter(n -> n % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6, 8, 10]
6.3.3 并行查找
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> anyEven = numbers.parallelStream().filter(n -> n % 2 == 0).findAny();
System.out.println(anyEven.orElse(null)); // 输出: 6 (或流中的任意一个偶数)
6.4 注意事项
  • 线程安全:并行流在多个线程上并行处理数据,因此在使用并行流时需要注意线程安全问题。特别是当操作涉及共享状态时,需要确保线程安全。
  • 副作用:并行流不适合有副作用的操作,因为并行处理可能导致不可预测的结果。
  • 性能:虽然并行流可以提高处理速度,但并不是所有情况都适合使用并行流。对于小数据集或简单操作,使用普通流可能更高效。并行流的开销包括任务划分、线程调度和结果合并,这些开销可能抵消并行处理带来的性能提升。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值