Java Stream 必须掌握的几种用法

java,stream,必须,掌握,几种,用法 · 浏览次数 : 3

小编点评

**代码摘要** ```java // userList.stream().forEach(u -> u.setAge(null)); // StringBuilder sb = new StringBuilder();userList.stream().peek(u -> sb.append(u.getUsername() + " ")); // Set<Integer, User> ageSet = userList.stream().map(User::getAge).collect(Collectors.toSet()); // Map<Integer, User> userIdToUserMap = userList.stream().collect(Collectors.toMap(User::getId, u -> u, (k1, k2) -> k1)); // System.out.println("userIdToUserMap {}\n", userIdToUserMap); ``` **代码功能** 1. 获取用户列表中的所有用户 id 和 username。 2. 将所有用户 id 和 username 的集合转换为 Set。 3. 创建一个 Map,其中键是用户 id,值是用户对象。 4. 将 Map 的键值集合转换为一个 Set。 5. 获取所有用户 id 和 username 的集合,并将其转换为 Map。 6. 打印用户 id 和 username 的 Map。 **异常** 当用户 id 重复时,会抛出异常 `IllegalStateException`,因为 Map 的键值必须唯一。 **排版** 代码中的 `StringBuilder sb` 用于存储用户 id 和 username 的集合,而 `Set` 用于存储所有用户 id 和 username 的集合。`Map` 用于存储用户 id 和 username 的映射。 **输出结果** 代码将打印以下结果: ``` 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)} ```

正文

Stream 是 Java8 推出的一套简化集合、数组操作的 API,掌握 Stream 的用法将极大的提升我们的编程能力。
image

流的获取

通过 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);

与Java Stream 必须掌握的几种用法相似的内容:

Java Stream 必须掌握的几种用法

Stream 是 Java8 推出的一套简化集合、数组操作的 API,掌握 Stream 的用法将极大的提升我们的编程能力。 流的获取 通过 Stream 自带的 API 获取: // 通过传入可变参数构造 static Stream of(T... values); // 指定一个常量

【进阶篇】使用 Stream 流对比两个集合的常用操作分享

Stream API 是 Java 8 中最为重要的更新之一,是处理集合的关键抽象概念,也是每个 Java 后端开发人员都必须无条件掌握的内容。 在之前的开发中,遇到了这样的需求:记录某个更新操作之前的数据作为日志内容,之后可以供管理员在页面上查看该日志。

知识点笔记(java / 数据库)

1-java stream peek vs map;; 2-java各种map;; 3-mysql列变行;; 4-java @Conditional;; 5-redis命名空间;; 等等等等...

Java Lambda Stream

java list 中的字符是否包括在另一个 list 中 ,::方法使用

Java多线程-ThreadPool线程池-3(五)

除了可以通过ThreadPoolExecutor自定义线程池外,同Stream API中的Collectors一样,多线程里的Executors类也提供了一组相关的线程池工具,可以直接拿来用,不用考虑用什么队列合适的问题。 Javac除了传统的四大线程池工具: 1、newFixedThreadPoo

8个实用的Java Streams API

分享8个开箱即用的API,方便日常处理集合。 1. 快速过滤空值:Stream.ofNullable 该方法是在 Java 9 中引入的,有助于过滤集合中的所有空值,从而可能使我们避免空指针异常。 在下面的示例中,有一个包含 null 的List。此时,我们可以使用Stream.ofNullable

聊一聊Java中的Steam流

在我们的日常编程任务中,对于集合的制造和处理是必不可少的。当我们需要对于集合进行分组或查找的操作时,需要用迭代器对于集合进行操作,而当我们需要处理的数据量很大的时候,为了提高性能,就需要使用到并行处理,这样的处理方式是很复杂的。流可以帮助开发者节约宝贵的时间,让以上的事情变得轻松。

为什么不推荐使用Linq?

相信很多.NETer看了标题,都会忍不住好奇,点进来看看,并且顺便准备要喷作者! 这里,首先要申明一下,作者本人也非常喜欢Linq,也在各个项目中常用Linq。 我爱Linq,Linq优雅万岁!!!(PS:顺便吐槽一下,隔壁Java从8.0版本推出的Streams API,抄了个四不像,一点都不优雅

Java异步判断线程池所有任务是否执行完成的方法

本文详细介绍了Java异步判断线程池所有任务是否执行完成的方法,分别介绍了使用ExecutorService和CountDownLatch的方法示例、使用ExecutorService的invokeAll方法和Future列表的方法示例、使用ExecutorService来异步执行多个Callabl...

面试官:Java线程可以无限创建吗?

哈喽,大家好,我是世杰。 ⏩本次给大家介绍一下操作系统线程和Java的线程以及二者的关联 1. 面试连环call Java线程可以无限创建吗? Java线程和操作系统线程有什么关联? 操作系统为什么要区分内核态和用户态? ⏩要想解答这些问题,我们要先从操作系统线程开始说起,让我们开始吧�