Stream是Java 8的一大亮点,与 java.io包中的InputStream和OutputStream不同,Java 8中的Stream是对集合对象功能的增强,专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作。Stream API借助于同样新出现的Lambda表达式,极大地提高编程效率
使用StreamAPI分三步
使用如下方法可以获得流
代码演示
// 1, 通过java.util.Collection提供的stream()或parallelStream()方法获得一个流
List<String> list = Lists.newArrayList("Jack", "Tom");
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.parallelStream();
// 2, 通过java.util.Arrays提供的stream()方法将一个数组转换成流
String[] arr = {"Jack", "Tom"};
Stream<String> stream3 = Arrays.stream(arr);
// 3, 通过java.util.stream.Stream提供的of()方法得到一个流
Stream<String> stream4 = Stream.of("Jack", "Tom");
// 4, 通过java.util.stream.Stream提供的iterate()方法获取一个流
Stream<Integer> stream5 = Stream.iterate(0, (x) -> x + 5);
// 5, 通过java.util.stream.Stream提供的generate()方法获取一个流
Stream<Double> stream6 = Stream.generate(Math::random);
多个中间操作连起来类似一个流水线,在终止操作之前,中间操作不会对数据进行任何处理,直到终止操作时才会一次性全部处理中间操作
代码演示
List<Student> list = Lists.newArrayList(new Student(1001L, 20, "Jack"),
new Student(1002L,25, "Tom"),
new Student(1003L,30, "Bob"),
new Student(1004L,35, "Chen"),
new Student(1004L,35, "Chen"));
// 中间操作 .filter() 过滤流中的元素; .limit() 截取流中的元素; .skip() 跳过元素; .distinct() 元素去重
Stream<Student> stream = list.stream()
.filter((s) -> s.getAge() >= 25)
.limit(5)
.skip(1)
.distinct();
// 终止操作
stream.forEach(System.out::println);
// 中间操作 .map() 映射; .flatMap() 将多个流转换为1个流; .mapToDouble(); .mapToInt(); .mapToLong()
Stream<Character> stream1 = list.stream()
.map(Student::getName)
.flatMap(StreamApiTest::nameCharacter);
// 终止操作
stream1.forEach(System.out::println);
// 中间操作 .sorted() 自然排序; .sorted() 自定义排序
Stream<Student> stream2 = list.stream()
.sorted(Comparator.comparingInt(Student::getAge));
// 终止操作
stream2.forEach(System.out::println);
// 补充
private static Stream<Character> nameCharacter(String name) {
List<Character> cList = Lists.newArrayList();
for (Character c : name.toCharArray()) {
cList.add(c);
}
return cList.stream();
}
代码演示
List<Student> list = Lists.newArrayList(new Student(1001L, 20, "Jack"),
new Student(1002L,25, "Tom"),
new Student(1003L,10, "Bob"),
new Student(1004L,35, "Chen"),
new Student(1004L,35, "Chen"));
Stream<Student> stream = list.stream()
.filter((s) -> s.getAge() >= 25);
// 终止操作
// .allMatch() 是否全部元素匹配; .anyMatch() 是否至少一个元素匹配; .noneMatch() 是否所有元素都不匹配;
// .findAny() 返回任意一个元素; .findFirst() 返回第一个元素
// .count() 返回元素总数
// .max() 返回最大元素; .min() 返回最小元素
// .forEach() 内部迭代所有元素
boolean j = stream
.anyMatch((s) -> s.getName().contains("C"));
System.out.println(j);
// 终止操作 .reduce() 将流中的元素结合起来
int sum = stream
.mapToInt(Student::getAge)
.reduce(0, Integer::sum);
System.out.println(sum);
// 终止操作 .collect() 将元素汇总
// 收集到List
List<Student> collect = stream.collect(Collectors.toList());
// 收集到Set
Set<Student> collect1 = stream.collect(Collectors.toSet());
// 收集到创建的集合
ArrayList<Student> collect2 = stream.collect(Collectors.toCollection(ArrayList::new));
// 收集元素的个数
Long collect3 = stream.collect(Collectors.counting());
// 求和
Integer collect4 = stream.collect(Collectors.summingInt(Student::getAge));
// 求平均值
Double collect5 = stream.collect(Collectors.averagingInt(Student::getAge));
// 得到统计值
IntSummaryStatistics collect6 = stream.collect(Collectors.summarizingInt(Student::getAge));
// 连接字符串
String collect7 = stream.map(Student::getName).collect(Collectors.joining());
// 得到最大值
Optional<Student> collect8 = stream.collect(Collectors.maxBy(Comparator.comparingInt(Student::getAge)));
// 得到最小值
Optional<Student> collect9 = stream.collect(Collectors.minBy(Comparator.comparingInt(Student::getAge)));
// 规约
Integer collect10 = stream.collect(Collectors.reducing(0, Student::getAge, Integer::sum));
// 对收集器的结果进行转换
Integer collect11 = stream.collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
// 转map
Map<Long, List<Student>> collect12 = stream.collect(Collectors.groupingBy(Student::getId));
// boolean区分
Map<Boolean, List<Student>> collect13 = stream.collect(Collectors.partitioningBy((s) -> s.getAge() > 20));
串行流与并行流:可以通过 .sequential() 和 .parallel() 在串行流与并行流之间做切换
代码演示
StopWatch watch = new StopWatch();
watch.start("耗时");
LongStream stream = LongStream.rangeClosed(0, 10000000000L);
long sum = stream
.parallel()
.reduce(0, Long::sum);
watch.stop();
// .sequential() 耗时18225ms; .parallel() 耗时892ms
System.out.println(watch.prettyPrint());