java8 stream distinct by key

本文介绍了一种使用Java Stream API结合Lambda表达式去除集合中重复元素的方法。通过自定义Predicate,利用ConcurrentHashMap实现高效的去重逻辑。适用于处理带有唯一键如设备MAC地址的数据集。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
deviceRecords.stream().filter(distinctByKey(deviceRecord -> deviceRecord.getDeviceMac())).forEach(deviceRecord -> {
    System.out.println(deviceRecord.getDeviceMac());
});

<think>我们正在讨论JavaStream流的使用教程和示例代码。根据引用内容,StreamAPI是Java8引入的,用于处理集合数据的声明式编程模型。它允许链式操作,包括中间操作(如过滤、映射)和终端操作(如聚合、收集)。我们将逐步介绍Stream的概念、核心特性和代码示例。关键点:1.Stream不是数据结构,而是对数据源(如集合、数组)的计算操作序列。2.Stream操作分为中间操作(返回Stream)和终端操作(产生结果或副作用)。3.Stream支持顺序和并行处理。使用步骤:1.创建Stream:从数据源(集合、数组等)获取流。2.中间操作:对数据进行处理(过滤、映射等),可多次调用。3.终端操作:触发计算并得到结果。示例代码将涵盖:-创建Stream-常用中间操作(filter,map,sorted,distinct等)-常用终端操作(forEach,collect,reduce等)-并行流注意:引用中提到了双列集合(如HashMap)获取流的方法,以及从文件读取行到流的方法,这些也会包含在示例中。下面开始详细讲解和示例。</think>### Java Stream流使用教程与示例代码 Java Stream API(Java 8+)提供了一种**声明式数据处理**方式,核心优势在于简化集合操作、支持并行处理和提高代码可读性。以下是关键概念和使用方法: #### 一、Stream核心特性 1. **非数据结构**:不存储数据,仅定义计算流水线 2. **惰性求值**:终端操作触发实际计算(如`collect()`) 3. **不可重用**:流消费后不可重复使用 4. **并行能力**:`parallelStream()`自动利用多核处理器[^1] #### 二、创建Stream的5种方式 ```java // 1. 集合创建 List<String> list = Arrays.asList("a", "b", "c"); Stream<String> stream1 = list.stream(); // 2. 数组创建 String[] array = {"x", "y", "z"}; Stream<String> stream2 = Arrays.stream(array); // 3. 值创建 Stream<Integer> stream3 = Stream.of(1, 2, 3); // 4. 文件创建(引用示例扩展) try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) { lines.forEach(System.out::println); } // 自动关闭资源[^4] // 5. 双列集合(Map) Map<String, Integer> map = new HashMap<>(); map.put("A", 100); map.entrySet().stream() // 获取Entry流 .forEach(e -> System.out.println(e.getKey() + ":" + e.getValue())); [^3] ``` #### 三、常用中间操作(Intermediate Operations) ```java List<String> words = Arrays.asList("apple", "banana", "cherry", "date"); // 1. 过滤 filter() words.stream() .filter(s -> s.length() > 5) // 保留长度>5的单词 // 2. 映射 map() .map(String::toUpperCase) // 转为大写 // 3. 排序 sorted() .sorted(Comparator.reverseOrder()) // 逆序排序 // 4. 去重 distinct() .distinct() // 5. 截取 limit()/skip() .skip(1) // 跳过第一个元素 .limit(2); // 保留后续2个元素 ``` #### 四、终端操作(Terminal Operations) ```java // 1. 遍历 forEach() stream.forEach(System.out::println); // 2. 收集 collect() List<String> result = stream.collect(Collectors.toList()); // 3. 聚合 reduce() Optional<Integer> sum = Stream.of(1, 2, 3) .reduce(Integer::sum); // 求和=6 // 4. 匹配检查 boolean anyMatch = words.stream().anyMatch(s -> s.startsWith("a")); // true boolean allMatch = words.stream().allMatch(s -> s.length() > 3); // true // 5. 统计 count() long count = words.stream().count(); // 4 ``` #### 五、并行流实战示例 ```java List<Integer> numbers = IntStream.rangeClosed(1, 1000000).boxed().collect(Collectors.toList()); // 顺序流 long startSeq = System.currentTimeMillis(); numbers.stream().map(n -> n * 2).collect(Collectors.toList()); System.out.println("顺序耗时: " + (System.currentTimeMillis()-startSeq) + "ms"); // 并行流(利用多核) long startPar = System.currentTimeMillis(); numbers.parallelStream().map(n -> n * 2).collect(Collectors.toList()); System.out.println("并行耗时: " + (System.currentTimeMillis()-startPar) + "ms"); ``` > **注意**:并行流适用于大数据集,小数据集可能因线程开销反而更慢[^2] #### 六、实战应用场景 1. **数据转换**:集合元素批量处理 ```java List<User> users = ...; List<String> names = users.stream() .map(User::getName) .collect(Collectors.toList()); ``` 2. **条件筛选**:数据库式查询 ```java List<Product> expensiveProducts = products.stream() .filter(p -> p.getPrice() > 1000) .filter(p -> "Electronics".equals(p.getCategory())) .collect(Collectors.toList()); ``` 3. **分组统计**(使用`Collectors.groupingBy`) ```java Map<String, Long> countByCategory = products.stream() .collect(Collectors.groupingBy( Product::getCategory, Collectors.counting() )); ``` #### 七、最佳实践与注意事项 1. **避免副作用**:操作应保持无状态(不修改外部变量) 2. **优先使用方法引用**:`map(String::length)` 优于 `map(s -> s.length())` 3. **谨慎使用并行**: - 数据量 > 10万时考虑 - 避免在共享资源操作中使用 4. **关闭IO相关流**:如`Files.lines()`需用try-with-resources[^4] > Stream API通过减少样板代码和提供声明式语法,显著提升开发效率和代码可维护性[^2]。但在性能敏感场景仍需基准测试验证。 --- ### 相关问题 1. Stream流中的`map()`和`flatMap()`有什么区别? 2. 如何用Stream实现分页查询功能? 3. 并行流处理可能引发哪些线程安全问题? 4. Java Stream与Kotlin序列(Sequence)有何异同? 5. 哪些场景不适合使用Stream API?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值