新的
java.util.stream
包中的类提供了一个Stream API,以支持对元素流的函数式操作。 Stream API集成到Collections API中,可以对集合进行批量操作,比如筛选、排序、映射等。下面就来体验一下如何使用 Stream API 来简化一些代码。
就跟把大象装进冰箱需要几步一样,操作 Stream 也同样需要 3 步:
1. 第一步:创建 Stream,通常有三种方式来创建一个 Stream
- 使用
List
集合
Stream<Object> stream = new ArrayList<>().stream();
- 使用
Arrays
工具类
IntStream stream = Arrays.stream(new int[]{1, 2, 3});
- 使用
Stream.of()
方法
Stream<Object> stream = Stream.of();
2. 第二步:中间操作
先来一些基础数据
static List<Emploee> emps = new ArrayList<>();
static {
emps.add(new Emploee(1, "张三", 15, 9999.99));
emps.add(new Emploee(2, "李四", 25, 4444.99));
emps.add(new Emploee(3, "王五", 85, 6666.99));
emps.add(new Emploee(4, "赵六", 55, 2222.99));
emps.add(new Emploee(5, "田七", 40, 5555.99));
}
(1). 筛选:
- filter(Predicate<? super T> predicate):比如输出年龄大于30岁的
@Test
public void test1(){
emps.stream()
.filter(e -> e.getAge() > 30)
.forEach(System.out::println);
}
// 输出
Emploee{id=3, name='王五', age=85, wage=6666.99}
Emploee{id=4, name='赵六', age=55, wage=2222.99}
Emploee{id=5, name='田七', age=40, wage=5555.99}
- limit(long maxSize):筛选前 maxSize 条数据
@Test
public void test2(){
emps.stream()
.limit(3)
.forEach(System.out::println);
}
// 输出
Emploee{id=1, name='张三', age=15, wage=9999.99}
Emploee{id=2, name='李四', age=25, wage=4444.99}
Emploee{id=3, name='王五', age=85, wage=6666.99}
- skip(long n):跳过前 n 条数据
@Test
public void test2(){
emps.stream()
.skip(3)
.forEach(System.out::println);
}
// 输出
Emploee{id=4, name='赵六', age=55, wage=2222.99}
Emploee{id=5, name='田七', age=40, wage=5555.99}
- distinct():去重,保证数据的唯一性
@Test
public void test4(){
emps.add(new Emploee(6, "张三", 25, 8888.88));
emps.add(new Emploee(6, "张三", 25, 8888.88));
emps.add(new Emploee(6, "张三", 25, 8888.88));
emps.stream()
.distinct()
.forEach(System.out::println);
}
// 输出
Emploee{id=1, name='张三', age=15, wage=9999.99}
Emploee{id=2, name='李四', age=25, wage=4444.99}
Emploee{id=3, name='王五', age=85, wage=6666.99}
Emploee{id=4, name='赵六', age=55, wage=2222.99}
Emploee{id=5, name='田七', age=40, wage=5555.99}
Emploee{id=6, name='张三', age=25, wage=8888.88}
// 以上输出结果基于 Emploee 实现了 hashCode 和 equals 方法
(2). 映射
- map(Function<? super T, ? extends R> mapper)
@Test
public void test5(){
emps.clear();
emps.add(new Emploee(7, "tom", 15, 999.99));
emps.add(new Emploee(8, "jerry", 25, 888.88));
emps.stream()
.map(e -> e.getName().toUpperCase())
.forEach(System.out::println);
}
// 输出
TOM
JERRY
// 根据 map 的特征,即 K-V 对的格式,其实映射关系就是下面这样
tom->TOM
jerry->JERRY
(3). 排序
- sorted():默认排序
注意
:可能会抛出异常,需要对应的类实现 Comparable 接口并重写 compareTo(Object o) 方法 - sorted(Comparator<? super T> comparator):定制排序
3. 第三步:终止操作
(1). 匹配与查找(相对比较简单)
- allMatch 检查是否匹配所有元素
- anyMatch 检查是否至少匹配一个元素
- noneMatch 检查是否没有匹配的元素
- findFirst 返回流中第一个元素
- findAny 返回流中任意元素
- count 返回流中元素的总数
- max 返回流中最大值
- min 返回流中最小值
- forEach 内部迭代
(2). 归约
- T reduce(T identity, BinaryOperator<T> accumulator):可以将流中元素反复结合起来,得到一个值,返回 T,比如累加操作。
- Optional<T> reduce(BinaryOperator<T> accumulator):可以将流中元素反复结合起来,得到一个值,返回 Optional<T>
(3). 收集
- collect(Collector<? super T, A, R> collector):接收一个 Collector 接口的实现,用于给 Stream 中的元素做一个汇总
@Test
public void test7(){
emps.add(new Emploee(6, "张三", 25, 8888.88));
Map<String, List<Emploee>> map = emps.stream()
.collect(Collectors.groupingBy(e -> e.getName()));
Set<Map.Entry<String, List<Emploee>>> entries = map.entrySet();
entries.forEach(System.out::println);
}
// 输出
李四=[Emploee{id=2, name='李四', age=25, wage=4444.99}]
张三=[Emploee{id=1, name='张三', age=15, wage=9999.99}, Emploee{id=6, name='张三', age=25, wage=8888.88}]
王五=[Emploee{id=3, name='王五', age=85, wage=6666.99}]
赵六=[Emploee{id=4, name='赵六', age=55, wage=2222.99}]
田七=[Emploee{id=5, name='田七', age=40, wage=5555.99}]
上面介绍了操作 Stream 的基本步骤以及一些实际案例,有一些我还没有实际使用过,就目前来讲我用的最多的就是映射和收集,比如根据数据库查询出来的结果进行分组展示,就会省略一些数据库查询,节省接口请求时间,加快接口相应速度。
网友评论