【Java Stream API去重与筛选实战】:distinct与filter的巧妙应用
发布时间: 2024-12-10 02:25:05 阅读量: 17 订阅数: 12
Java中对List去重 Stream去重的解决方法
![Java Stream API的高效数据处理](https://img-blog.csdnimg.cn/img_convert/c630c646ce9e32319c8b0fbafad8a370.jpeg)
# 1. Java Stream API简介
## 简介
Java Stream API是Java 8中引入的一个新特性,它提供了一种高效且易于理解的方式来处理集合(Collection)数据。Stream API利用函数式编程的优势,支持多种方式对集合进行操作,包括过滤、映射、排序、查找、聚合等。
## 特点
Stream API的一个显著特点就是它的操作具有延迟执行(Lazy Evaluation)的特性。这意味着大部分的操作并不会立即执行,而是会延迟到真正需要结果的时候才进行处理。这种机制使得多个操作可以以链式的方式组合起来,最终一次性完成,极大提升了性能和可读性。
## 基本用法
下面是一个简单的示例,演示了如何使用Stream API来处理一个List集合,并打印出集合中所有的偶数元素:
```java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream() // 创建流
.filter(n -> n % 2 == 0) // 筛选偶数
.collect(Collectors.toList()); // 收集结果
evenNumbers.forEach(System.out::println); // 打印结果
}
}
```
这段代码首先创建了一个包含数字的List,然后使用`.stream()`生成流,`.filter()`方法筛选出偶数,并最终收集到一个新的List中。`.forEach()`方法用于遍历并打印出筛选后的结果。这个例子简单展示了如何使用Stream API进行基本操作。
# 2. Stream API中的去重操作
### 2.1 distinct方法的基本用法
#### 2.1.1 distinct的原理和行为
`distinct`方法是Java Stream API中用于去除流中重复元素的一个重要方法。它基于元素的自然顺序或自定义比较器来确保流中的元素唯一性。当使用`distinct`方法时,它会检查流中的元素是否相等,即调用元素的`equals`方法进行比较。在内部,它实际上是使用了`HashSet`来进行元素的唯一性检查。
- 对于基础类型的流,如`IntStream`、`DoubleStream`或`LongStream`,`distinct`直接利用它们的`equals`和`hashCode`方法。
- 对于对象类型的流,如`Stream<T>`,则需要对象类型的类正确实现了`equals`和`hashCode`方法,以便正确识别重复的对象。
这里需要注意,由于`distinct`方法内部使用了`HashSet`,因此它不会保留任何元素的原始顺序,而是以任意的顺序返回不重复的元素。
#### 2.1.2 去重操作的实践案例
假设有一个商品类`Product`,它包含了商品的ID、名称和价格。如果想要创建一个商品流,然后去除重复的商品,可以如下使用`distinct`方法:
```java
class Product {
private final int id;
private final String name;
private final double price;
// 构造器、getter和equals以及hashCode方法省略
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Product product = (Product) obj;
return id == product.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
// 示例代码
List<Product> uniqueProducts = products.stream()
.distinct()
.collect(Collectors.toList());
```
### 2.2 去重高级技巧
#### 2.2.1 结合自定义对象去重
在实际开发中,我们可能会遇到需要基于对象的多个属性进行去重的情况。比如,需要根据商品的ID和名称组合来确定商品的唯一性。这种情况下,需要实现自定义的`equals`和`hashCode`方法,或者在`distinct`中使用复合键比较。
以下是一个示例:
```java
public class ProductKey {
private final int id;
private final String name;
public ProductKey(int id, String name) {
this.id = id;
this.name = name;
}
// equals和hashCode方法省略
}
// 示例代码
Stream<Product> stream = products.stream();
Stream<Product> distinctStream = stream.map(p -> new ProductKey(p.getId(), p.getName()))
.distinct()
.map(key -> products.stream().filter(p -> key.equals(new ProductKey(p.getId(), p.getName())))
.findFirst().get());
```
#### 2.2.2 复合条件去重策略
当需要根据多个属性进行去重时,我们可以利用`Collectors.toMap`来创建一个映射表,其中键是由复合属性创建的键,值是元素本身。之后利用`Map`的特性进行去重。
```java
Map<ProductKey, Product> productMap = products.stream()
.collect(Collectors.toMap(p -> new ProductKey(p.getId(), p.getName()), p -> p));
List<Product> uniqueProducts = new ArrayList<>(productMap.values());
```
这种方式会抛出`IllegalStateException`,如果存在重复的键,可以选择合并策略来解决,比如保留价格最高的商品。
```java
Map<ProductKey, Product> productMap = products.stream()
.collect(Collectors.toMap(p -> new ProductKey(p.getId(), p.getName()), p -> p, (p1, p2) -> p1.getPrice() > p2.getPrice() ? p1 : p2));
List<Product> uniqueProducts = new ArrayList<>(productMap.values());
```
这种方式通过使用自定义的合并函数,选择性地保留了具有更高价格的商品。通过这种去重高级技巧,我们可以灵活地处理各种复杂的去重需求。
# 3. Stream API中的筛选操作
##
0
0