流式操作是Java 8中引入的一项重要特性,提供了更加声明式、函数式的编程风格。在Java中,“流”(Stream)是数据的抽象,是一种元素的序列,可以对其进行各种操作。
流式操作的基础是流的生产和操作(Operation)。生产源可以是集合、数组或者I/O通道等。
操作分为中间操作和结束操作。中间操作包括filter、map等,结束操作包括collect、count等。流式操作不会更改原来的集合,会返回新的集合。
流式操作如果不调用终止方法,中间的操作不会执行。
创建流
要进行流式操作首先要创建流也就是Stream,java流可以从集合、数值或者文件中创建,下面是一些创建流的示例:
//由集合创建流
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
Stream<String> stream = list.stream();
//由数组创建
int[] array = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(array);
//由值创建
Stream<String> stream = Stream.of("Apple", "Banana", "Cherry");
//通过方法创建,每个元素都是上个元素的值加2,限制限制为前十个元素
Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(10);
//从文件创建流
Path path = Paths.get("file.txt");
Stream<String> stream = Files.lines(path);
//连接两个流
Stream<String> stream1 = Stream.of("A", "B", "C");
Stream<String> stream2 = Stream.of("X", "Y", "Z");
Stream<String> newStream = Stream.concat(stream1, stream2);
//使用Stream.generate,创建了一个包含10个0-1之间的随机数的Double流
Stream<Double> randomNumbers = Stream.generate(Math::random).limit(10);
操作流
流的操作分为中间操作和终止操作
中间操作返回Stream对象本身,可以将多个中间操作连接起来使用,中间操作在没有终止操作时不会对数据进行处理,只有遇到终止操作时才会进行处理。
以下是一些中间操作的示例:
//filter用于过滤
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // [2, 4, 6]
//map用于数据转换,接收函数作为参数,映射到每个数据上,并返回新的数据
List<String> names = Arrays.asList("John", "Jane", "Jack");
List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList()); // [JOHN, JANE, JACK]
//peek方法可以在流的每个元素上执行一个操作,而不会改变流的内容,可用于debug
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> result = numbers.stream()
.peek(num -> System.out.println("will filter: " + num)) // Before filter
.filter(n -> n % 2 == 0)
.peek(num -> System.out.println("filtered: " + num)) // After filter
.map(n -> n * 2)
.peek(num -> System.out.println("doubled: " + num)) // After map
.collect(Collectors.toList());
//flatMap用于将多个流连接成一个流
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("Apple", "Banana"),
Arrays.asList("Orange", "Mango", "Peach")
);
List<String> listOfAllFruits = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList()); // [Apple, Banana, Orange, Mango, Peach]
//distinct可以对数据进行去重
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList()); // [1, 2, 3, 4, 5]
//sort用于对数据进行排序,可接收Comparator接口作为参数,进行自定义排序
List<String> sortedNamesDesc = names.stream()
.sorted((name1, name2) -> name2.length() - name1.length())
.collect(Collectors.toList());
//limit:用于截取Stream的前n个元素。
//skip:用于丢弃前n个元素。
以下是一些终止操作的示例:
forEach: 对流中的每个元素执行操作
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::println);
toArray: 将流中的元素转换为数组
Integer[] array = list.stream().toArray(Integer[]::new);
reduce: 聚合流中的元素
Optional<Integer> sum = list.stream().reduce(Integer::sum);
collect: 将流转换为其他形式, 例如转换为 List, Set 或Map
List<Integer> newList = list.stream().collect(Collectors.toList());
min 和 max: 找到流中的最小或最大元素
Optional<Integer> min = list.stream().min(Integer::compare);
Optional<Integer> max = list.stream().max(Integer::compare);
count: 计算流中的元素数量
long count = list.stream().count();
anyMatch, allMatch 和 noneMatch: 检查流中的元素是否匹配给定的条件
boolean anyMatch = list.stream().anyMatch(num -> num > 3);
boolean allMatch = list.stream().allMatch(num -> num > 0);
boolean noneMatch = list.stream().noneMatch(num -> num < 0);
findFirst 和 findAny: 返回流中的第一个或任意一个元素
Optional<Integer> first = list.stream().findFirst();
Optional<Integer> any = list.stream().findAny();