首页   快速返回

JAVA8 stream 集合处理     所属分类 java


Stream lambda

Stream 流  
将集合转换为 流 ,元素序列
通过声明方式,对集合中的每个元素进行一系列并行或串行的流水线操作。

数据源  流 中间操作 终端操作

List<T> 集合转换为 Stream<T> 类型的流

过滤 排序 类型转换 
终端操作,可以把 Stream 转换回集合类型 或者  打印  计数 求和 求平均 计算最大值最小值 等 

List<String> newList = list.stream().map(Person::getName).sorted().limit(10).collect(Collectors.toList());


List<String> list = Arrays.asList("x","a","d","c");
Stream<String> stream = list.stream().sorted().limit(3);
List<String> newList1 = stream.collect(Collectors.toList());
// java.lang.IllegalStateException: stream has already been operated upon or closed
// List<String> newList2 = stream.collect(Collectors.toList());

流只能迭代一次


stream() 
parallelStream()

filter(T -> boolean)
保留 boolean 为 true 的元素

保留年龄为 20 的 person 
list = list.stream().filter(person -> person.getAge() == 20).collect(toList());

distinct()  去除重复元素
通过 equals 方法 判断两个元素是否相等

sorted() 
sorted((T, T) -> int)

如果流中的元素实现了 Comparable 接口,可以直接调用 sorted() 排序

根据年龄大小来比较:
list = list.stream().sorted((p1, p2) -> p1.getAge() - p2.getAge()).collect(toList());
           
list = list.stream().sorted(Comparator.comparingInt(Person::getAge)).collect(toList());


limit(long n) 返回前 n 个元素
skip(long n) 跳 前 n 个元素

map(T -> R)
将流中的每一个元素 T 映射为 R(类似类型转换)

List<String> newlist = list.stream().map(Person::getName).collect(toList());


flatMap(T -> Stream<R>)
将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流

List<String> list = new ArrayList<>();
list.add("are you ok");
list.add("i am fine");

list = list.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(toList());

anyMatch(T -> boolean)
boolean b = list.stream().anyMatch(person -> person.getAge() == 20);

allMatch(T -> boolean)
noneMatch(T -> boolean)

Optional<T> findAny() 
Optional<T> findFirst()

reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)

用于组合流中的元素,如求和,求积,求最大值等

求和

计算年龄总和:
int sum = list.stream().map(Person::getAge).reduce(0, (a, b) -> a + b);
int sum = list.stream().map(Person::getAge).reduce(0, Integer::sum);
第一个参数为初始值

可以不提供初始值 ,返回 Optional
Optional<Integer> sum = list.stream().map(Person::getAge).reduce(Integer::sum);

long count()

collect()  
collect(toList())  collect(toSet())

forEach  
list.stream().forEach(System.out::println);




数值流
IntStream, DoubleStream, LongStream
使用原始类型  int,double,long   避免 Box unbox

流转换为数值流
mapToInt(T -> int) : return IntStream
mapToDouble(T -> double) : return DoubleStream
mapToLong(T -> long) : return LongStream

IntStream intStream = list.stream().mapToInt(Person::getAge);

数值流转换为流
Stream<Integer> stream = intStream.boxed();

数值流方法
sum()
max()
min()
average() 

数值范围
range 和 rangeClosed

闭区间  半开半闭区间

1 到 10 求和 
IntStream intStream = IntStream.rangeClosed(1, 10);
int sum = intStream.sum();

Optional 类 解决空指针问题

isPresent() 值存在时返回 true 
get()  获取当前值,值不存抛异常
orElse(T)  值存在时返回该值,否则返回 T 值


创建流

Stream<String> stream = Stream.of("hello", "Java8");
Stream.empty() 

根据数组创建流

Arrays.stream(T[])
Arrays.stream(int[])
Arrays.stream(double[])
Arrays.stream(long[])


// 只取索引第 1 到第 2 位 , 切片 [1,3)
int[] a = {1, 2, 3, 4};
Arrays.stream(a, 1, 3).forEach(System.out::println);

文件生成流
Stream<String> stream = Files.lines(Paths.get("data.txt"));

函数生成流
首元素为 0,之后依次加 2
Stream.iterate(0, n -> n + 2)
Stream.generate(Math :: random)
元素全为 1
Stream.generate(() -> 1)


collect 收集数据

toList
toSet
toCollection
toMap


List newlist = list.stream.collect(toList());

//  Map  Key 重复,报错
Map<Integer, Person> map = list.stream().collect(toMap(Person::getAge, p -> p));

汇总

long count = list.stream().collect(counting());
long count = list.stream().count();

summingInt ,summingLong ,summingDouble

int sum = list.stream().collect(summingInt(Person::getAge));

int sum = list.stream().mapToInt(Person::getAge).sum();

int sum = list.stream().map(Person::getAge).reduce(Interger::sum).get();

函数式编程通常提供多种方式来完成同一种操作


averagingInt,averagingLong,averagingDouble
Double average = list.stream().collect(averagingInt(Person::getAge));
OptionalDouble average = list.stream().mapToInt(Person::getAge).average();

注意返回类型不同!!!

summarizingInt,summarizingLong,summarizingDouble


IntSummaryStatistics stat = list.stream().collect(summarizingInt(Person::getAge));


取最值

Optional<Person> optional = list.stream().collect(maxBy(comparing(Person::getAge)));
Optional<Person> optional = list.stream().max(comparing(Person::getAge));


joining 连接字符串


String s = list.stream().map(Person::getName).collect(joining());

String s = list.stream().map(Person::getName).collect(joining(","));


groupingBy 分组

Map<Integer, List<Person>> map = list.stream().collect(groupingBy(Person::getAge));

按照年龄 age 分组,年龄相同的归为一组


多级分组

Map<Integer, Map<T, List<Person>>> map = list.stream().collect(groupingBy(Person::getAge, groupingBy(...)));

按组聚合
Map<Integer, Integer> map = list.stream().collect(groupingBy(Person::getAge, summingInt(Person::getAge)));


partitioningBy 分区
分区按照 true 和 false 来分

根据年龄是否小于等于20来分区
Map<Boolean, List<Person>> map = list.stream().collect(partitioningBy(p -> p.getAge() <= 20));


list.parallelStream()  并行流

流的可分解性

ArrayList 和 LinkedList, 前者在分解方面占优



性能 

Stream 的性能可能会低于传统的循环或者迭代器,甚至会低很多。

创建流的开销 流只能迭代一次 重复创建流  box unbox 

函数式编程 主要是为了提高编码开发效率 及 增强代码可读性




Java performance tutorial – How fast are the Java 8 streams?
https://jaxenter.com/java-performance-tutorial-how-fast-are-the-java-8-streams-118830.html

上一篇     下一篇
会计学习指南

Java8 parallelStream 并行处理实例及注意点

Java8新特性要点

springboot2 @RequestBody注解使用说明

边缘计算要点

詹姆斯写给伦纳德的一封信