详解JavaStream 掌握流式编程

1.定义

Java Stream 是 Java 8 引入的一个新特性,用于处理集合数据的操作。

Java Stream不是数据结构,是一种对数据进行操作和计算的方式。

提供一种声明性的方法来处理数据,类似于 SQL 语句。

2.关键点

声明性:使用 Stream API 可以用更少的代码、更清晰的逻辑来处理集合数据。

链式操作:Stream 操作可以链式调用,形成一条操作流水线。

惰性求值:Stream 的中间操作是惰性求值的,只有在终端操作时才会执行。

并行处理:Stream API 支持并行处理,可以利用多核处理器的优势。

3.流的分类

Java Stream 流可以根据操作类型和特性进行分类

3.1 按数据源分类
顺序流

(Sequential Stream)按顺序处理数据,一个接一个地处理。就像排队买票,每个人按顺序一个接一个地买票。

import java.util.Arrays;
import java.util.List;

public class SequentialStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 使用顺序流
        numbers.stream()
               .map(n -> n * n)
               .forEach(System.out::println);
    }
}


输出
1
4
9
16
25
并行流

(Parallel Stream)并行处理数据,多个数据可以同时处理。就像在多个窗口同时买票,每个人可以在不同的窗口同时买票。

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 使用并行流
        numbers.parallelStream()
               .map(n -> n * n)
               .forEach(System.out::println);
    }
}


输出(顺序可能不同)
1
4
9
16
25
3.2 按操作类型分类
中间操作

(Intermediate Operations):返回一个新的 Stream,可以链式调用。中间操作是惰性求值的,只有在终端操作时才会执行。

  • filter:过滤元素
  • map:映射每个元素到一个新的元素
  • flatMap:将每个元素转换为一个流,然后将这些流合并成一个流
  • sorted:对元素进行排序
  • distinct:去重
  • limit:截取前 N 个元素
  • skip:跳过前 N 个元素
List<String> list = Arrays.asList("a", "b", "c", "a");
list.stream()
    .filter(s -> s.startsWith("a"))
    .map(String::toUpperCase)
    .distinct()
    .sorted()
    .forEach(System.out::println);
解释:

创建流:list.stream() 创建了一个顺序流。

过滤操作:filter(s -> s.startsWith("a")) 过滤出以 "a" 开头的字符串来,保留下来以 "a" 开头的字符串,结果是 ["a", "a"]。

映射操作:map(String::toUpperCase) 将每个字符串转换为大写,结果是 ["A", "A"]。

去重操作:distinct() 去除重复的元素,结果是 ["A"]。

排序操作:sorted() 对元素进行排序,结果仍然是 ["A"](因为只有一个元素,不需要排序)。

终端操作:forEach(System.out::println) 打印每个元素。

最终输出:A
终端操作

(Terminal Operations):触发流的计算,返回一个结果。

  • forEach:对每个元素执行操作
  • collect:将流转换为其他形式
  • reduce:将流中的元素组合成一个值
  • count:计算流中元素的个数
  • anyMatch:检查是否至少有一个元素匹配给定的条件
  • allMatch:检查是否所有元素都匹配给定的条件
  • noneMatch:检查是否所有元素都不匹配给定的条件
  • findFirst:返回第一个元素
  • findAny:返回任意一个元素
ist<String> list = Arrays.asList("a", "b", "c", "a");
long count = list.stream()
                 .filter(s -> s.startsWith("a"))
                 .count();
System.out.println(count);
解释:
创建流:list.stream() 创建了一个顺序流。
过滤操作:filter(s -> s.startsWith("a")) 过滤出以 "a" 开头的字符串。
输入列表是 ["a", "b", "c", "a"]。
过滤后,结果是 ["a", "a"],因为只有这两个字符串以 "a" 开头。
计数操作:count() 计算流中元素的个数。
过滤后的结果是 ["a", "a"],所以元素个数是 2。
输出结果:System.out.println(count) 打印计数结果。
最终输出:2
3.3  按数据类型分类

IntStream:处理 int 类型的流。

import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // 创建一个包含 1 到 5 的 IntStream
        IntStream intStream = IntStream.rangeClosed(1, 5);

        // 计算流中所有元素的和
        int sum = intStream.sum();
        System.out.println("Sum: " + sum); // 输出: Sum: 15

        // 创建一个新的 IntStream 并打印每个元素
        IntStream.rangeClosed(1, 5).forEach(System.out::println);
        // 输出:
        // 1
        // 2
        // 3
        // 4
        // 5
    }
}

LongStream:处理 long 类型的流。

import java.util.stream.LongStream;

public class LongStreamExample {
    public static void main(String[] args) {
        // 创建一个包含 1 到 5 的 LongStream
        LongStream longStream = LongStream.rangeClosed(1, 5);

        // 计算流中所有元素的和
        long sum = longStream.sum();
        System.out.println("Sum: " + sum); // 输出: Sum: 15

        // 创建一个新的 LongStream 并打印每个元素
        LongStream.rangeClosed(1, 5).forEach(System.out::println);
        // 输出:
        // 1
        // 2
        // 3
        // 4
        // 5
    }
}

DoubleStream:处理 double 类型的流。

import java.util.stream.DoubleStream;

public class DoubleStreamExample {
    public static void main(String[] args) {
        // 创建一个包含 1.0 到 5.0 的 DoubleStream
        DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0, 4.0, 5.0);

        // 计算流中所有元素的和
        double sum = doubleStream.sum();
        System.out.println("Sum: " + sum); // 输出: Sum: 15.0

        // 创建一个新的 DoubleStream 并打印每个元素
        DoubleStream.of(1.0, 2.0, 3.0, 4.0, 5.0).forEach(System.out::println);
        // 输出:
        // 1.0
        // 2.0
        // 3.0
        // 4.0
        // 5.0
    }
}

4.获取流的常用方式

4.1 从集合获取流

ListSet 等集合可以直接调用 stream() 方法获取流。

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
4.2 从数组获取流

使用 Arrays.stream() 方法将数组转换为流。

String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
4.3 使用 Stream.of() 方法

直接使用 Stream.of() 方法创建

Stream<String> stream = Stream.of("a", "b", "c");
4.4 从文件获取流

使用 Files.lines() 方法读取文件并将其转换为流。

try (Stream<String> stream = Files.lines(Paths.get("file.txt"))) {
    stream.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}

 

5.常用方法用法

5.1 遍历 / 匹配(foreachfindmatch

forEach 方法用于遍历流中的每个元素并执行指定的操作。

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));

find 方法用于查找流中满足条件的第一个元素。

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
Optional<String> foundName = names.find(name -> name.startsWith("A"));

match 方法用于判断流中的元素是否满足指定的条件。

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
boolean allStartWithA = names.allMatch(name -> name.startsWith("A"));

5.2 聚合(maxmincount

max 方法用于获取流中的最大值。

Stream<Integer> numbers = Stream.of(1, 5, 3, 7, 2);
Optional<Integer> maxNumber = numbers.max(Integer::compareTo);

min 方法用于获取流中的最小值。

Stream<Integer> numbers = Stream.of(1, 5, 3, 7, 2);
Optional<Integer> minNumber = numbers.min(Integer::compareTo);

count 方法用于计算流中元素的数量。

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
long count = names.count();

5.3 映射(mapflatMap

map 方法用于将流中的每个元素按照指定的函数进行映射转换。

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
Stream<Integer> nameLengths = names.map(name -> name.length());

flatMap 方法用于将流中的每个元素转换为一个流,并将这些流扁平化合并为一个新的流。

Stream<List<String>> lists = Stream.of(List.of("A", "B"),
List.of("C", "D"));
Stream<String> flattened = lists.flatMap(list -> list.stream());

5.4 归约(reduce

reduce 方法用于对流中的元素进行归约操作,将多个元素合并为一个结果。

Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.reduce((a, b) -> a + b);

5.5 收集(collect

collect 方法用于将流中的元素收集到一个新的集合或其他数据结构中。

 归集(toListtoSettoMap

tream<String> names = Stream.of("Alice", "Bob", "Charlie");
List<String> nameList = names.collect(Collectors.toList());

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");
Set<String> nameSet = names.collect(Collectors.toSet());

Stream<Person> people = Stream.of(new Person("Alice", 20),
new Person("Bob", 30));
Map<String, Integer> nameAgeMap = people.collect(Collectors.toMap(Person::getName, Person::getAge));

 统计(countaveraging

Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);
Double average = numbers.collect(Collectors.averagingInt(num -> num));

分组(partitioningBygroupingBy

Stream<Person> people = Stream.of(new Person("Alice", 20), new Person("Bob", 30), new Person("Charlie", 20));Map<Boolean, List<Person>> partitioned = people.collect(Collectors.partitioningBy(person -> person.getAge() > 25));
Stream<Person> people = Stream.of(new Person("Alice", 20), new Person("Bob", 30), new Person("Charlie", 20));Map<Integer, List<Person>> grouped = people.collect(Collectors.groupingBy(Person::getAge));

接合(joining

Stream<String> names = Stream.of("Alice", "Bob", "Charlie");String joinedNames = names.collect(Collectors.joining(", "));

 排序(sorted

Stream<String> names = Stream.of("Charlie", "Alice", "Bob");Stream<String> sortedNames = names.sorted();

5.6 去重、合并(distinctskiplimit

distinct 方法用于去除流中的重复元素。

Stream<Integer> numbers = Stream.of(1, 2, 2, 3, 3, 3);Stream<Integer> distinctNumbers = numbers.distinct();

skip 方法用于跳过流中的前 n 个元素。

Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Stream<Integer> skippedNumbers = numbers.skip(2);

limit 方法用于获取流中的前 n 个元素。

Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Stream<Integer> limitedNumbers = numbers.limit(3);

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值