Java Stream 必须掌握的几种用法
Stream 是 Java8 推出的一套简化集合、数组操作的 API,掌握 Stream 的用法将极大的提升我们的编程能力。
流的获取
通过 Stream 自带的 API 获取:
// 通过传入可变参数构造
static<T> Stream<T> of(T... values);
// 指定一个常量 seed,生成从 seed 到常量 f(由 UnaryOperator 返回的值得到)的流
static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f);
// 生成一个空流
static<T> Stream<T> empty();
// 根据一个 Supplier 接口得到一个流
static<T> Stream<T> generate(Supplier<T> s);
举个例子:
List<String> list = Stream.of("lily", "lucy", "hock", "spider").collect(Collectors.toList());
// list: [lily, lucy, hock, spider]
log.info("list: {}", list);
...
List<Integer> list = Stream.iterate(1, i -> i * 2).limit(5).collect(Collectors.toList());
// list: [1, 2, 4, 8, 16]
log.info("list: {}", list);
...
List<Object> list = Stream.empty().collect(Collectors.toList());
// list: []
log.info("list: {}", list);
...
List<Object> list = Stream.generate(() -> new Random().nextInt(10)).limit(5).collect(Collectors.toList());
// list: [4, 1, 5, 5, 6]
log.info("list: {}", list);
将一个数组,转为 Stream 的话,除了 Stream.of 之外,还可以通过 Arrays 工具类获取:
static <T> Stream<T> stream(T[] array);
举个例子:
List<String> list = Arrays.stream(new String[]{"1", "2", "3"}).collect(Collectors.toList());
// list: [1, 2, 3]
log.info("list: {}", list);
将一个集合 Collection 接口(List、Set)转为 Stream 时,只需要通过 Collection 接口的默认方法:
// eg:new ArrayList<String>().stream();
default Stream<E> stream();
而将一个流转换为 Array 需要调用 .toArray,来看下:
String[] list = Stream.of("1", "2", "3").toArray(String[]::new);
// list: ["1","2","3"]
log.info("list: {}", JSON.toJSON(list));
流的常用操作
首先我们准备一个 User 对象的集合 userList:
List<User> userList = new ArrayList<>();
userList.add(User.builder().username("lily").age(20).id(1).build());
userList.add(User.builder().username("lucy").age(15).id(2).build());
userList.add(User.builder().username("hulu").age(30).id(3).build());
userList.add(User.builder().username("hulu").age(30).id(3).build());
userList.add(User.builder().username("rust").age(18).id(5).build());
过滤:
// 过滤出 age > 22 的
List<User> users = userList.stream().filter(u -> u.getAge() > 22).collect(Collectors.toList());
// users: [User(id=3, username=hulu, age=30), User(id=3, username=hulu, age=30)]
log.info("users: {}", users);
去重:
users = userList.stream().distinct().collect(Collectors.toList());
// users: [User(id=1, username=lily, age=20), User(id=2, username=lucy, age=15), User(id=3, username=hulu, age=30), User(id=5, username=rust, age=18)]
log.info("users: {}", users);
归约:
Integer ageTotal = userList.stream().map(User::getAge).reduce(0, Integer::sum);
// ageTotal: 113
log.info("ageTotal: {}", ageTotal);
匹配:
boolean hasHulu = userList.stream().anyMatch(u -> u.getUsername().equals("hulu"));
// hasHulu: true
log.info("hasHulu: {}", hasHulu);
boolean allPass18 = userList.stream().allMatch(u -> u.getAge() > 18);
// allPass18: false
log.info("allPass18: {}", allPass18);
boolean noneLessThen10 = userList.stream().noneMatch(u -> u.getAge() < 10);
// noneLessThen10: true
log.info("noneLessThen10: {}", noneLessThen10);
转换:
List<Integer> ageList = userList.stream().map(User::getAge).collect(Collectors.toList());
// ageList: [20, 15, 30, 30, 18]
log.info("ageList: {}", ageList);
List<Integer> list1 = CollUtil.newArrayList(1, 2, 3);
List<Integer> list2 = CollUtil.newArrayList(4, 5, 6);
List<Integer> list3 = CollUtil.newArrayList(7, 8, 9);
List<List<Integer>> cList1 = CollUtil.newArrayList();
cList1.add(list1);
cList1.add(list2);
cList1.add(list3);
List<Integer> lists = cList1.stream().flatMap(Collection::stream).collect(Collectors.toList());
// lists: [1, 2, 3, 4, 5, 6, 7, 8, 9]
log.info("lists: {}", lists);
排序:
users = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
// users: [User(id=2, username=lucy, age=15), User(id=5, username=rust, age=18), User(id=1, username=lily, age=20), User(id=3, username=hulu, age=30), User(id=3, username=hulu, age=30)]
log.info("users: {}", users);
遍历:
userList.stream().forEach(u -> u.setAge(null));
// userList: [User(id=1, username=lily, age=null), User(id=2, username=lucy, age=null), User(id=3, username=hulu, age=null), User(id=3, username=hulu, age=null), User(id=5, username=rust, age=null)]
log.info("userList: {}", userList);
StringBuilder sb = new StringBuilder();
userList.stream().peek(u -> sb.append(u.getUsername() + " ")).collect(Collectors.toList());
// sb: lily lucy hulu hulu rust
log.info("sb: {}", sb);
跳过:
users = userList.stream().skip(4).collect(Collectors.toList());
// users: [User(id=5, username=rust, age=null)]
log.info("users: {}", users);
计数:
long count = userList.stream().filter(u -> u.getAge() > 25).count();
// count: 2
log.info("count: {}", count);
List<Integer> list = Stream.iterate(0, s -> s + 2).limit(5).collect(Collectors.toList());
// list: [0, 2, 4, 6, 8]
log.info("list: {}", list);
大小值:
Integer maxAge = userList.stream().map(User::getAge).max(Integer::compareTo).get();
// maxAge: 30
log.info("maxAge: {}", maxAge);
Integer minAge = userList.stream().map(User::getAge).min(Integer::compareTo).get();
// minAge: 15
log.info("minAge: {}", minAge);
转 List:
List<Integer> ageList = userList.stream().map(User::getAge).collect(Collectors.toList());
// ageList: [20, 15, 30, 30, 18]
log.info("ageList: {}", ageList);
转 Set:
Set<Integer> ageSet = userList.stream().map(User::getAge).collect(Collectors.toSet());
// ageSet [18, 20, 30, 15]
log.info("ageSet {}", ageSet);
转 Map:
Map<Integer, User> userIdToUserMap = userList.stream().collect(Collectors.toMap(User::getId, u -> u));
// Exception in thread "main" java.lang.IllegalStateException: Duplicate key User(id=3, username=hulu, age=30)
// at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
// at java.util.HashMap.merge(HashMap.java:1255)
// at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
// at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
// at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
// at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
// at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
// at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
// at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
// at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
// at com.example.demo.StreamDemo.main(StreamDemo.java:52)
log.info("userIdToUserMap {}", userIdToUserMap);
以上代码执行会报错,特别注意当 key 重复时,需要手动指定 key 的覆盖策略:
Map<Integer, User> userIdToUserMap = userList.stream().collect(Collectors.toMap(User::getId, u -> u, (k1, k2) -> k1));
// userIdToUserMap {1=User(id=1, username=lily, age=20), 2=User(id=2, username=lucy, age=15), 3=User(id=3, username=hulu, age=30), 5=User(id=5, username=rust, age=18)}
log.info("userIdToUserMap {}", userIdToUserMap);
作者:程序员小波与Bug
出处:https://codetrips.cn
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:caiya928@aliyun.com
QQ:1419901425 联系我
如果喜欢我的文章,请关注我的公众号:程序员小波与Bug