如何用Java 8 Stream筛选各ID对应最高版本的对象?
Java 8 Stream实现按ID筛选最高版本对象
首先需要补充MyObj类的必要方法(原代码缺少构造方法、属性访问器,这是Stream操作的基础):
public class MyObj { private String ID; private String version; // 构造方法 public MyObj(String ID, String version) { this.ID = ID; this.version = version; } // Getter方法 public String getID() { return ID; } public String getVersion() { return version; } // 可选:重写toString方便调试 @Override public String toString() { return "MyObj{" + "ID='" + ID + '\'' + ", version='" + version + '\'' + '}'; } }
接下来是核心的Stream筛选逻辑,提供两种版本适配不同Java环境:
方案1:使用Java 9+的Version类(推荐,版本比较更准确)
如果项目基于Java 9及以上,直接用java.lang.Version处理版本字符串比较,避免自定义逻辑的漏洞:
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { MyObj obj1 = new MyObj("bike", "1.8"); MyObj obj2 = new MyObj("bike", "2.0"); MyObj obj3 = new MyObj("car", "3.4"); MyObj obj4 = new MyObj("car", "4.6"); List<MyObj> list = new ArrayList<>(); list.add(obj1); list.add(obj2); list.add(obj3); list.add(obj4); // 核心筛选逻辑 List<MyObj> result = list.stream() // 按ID分组 .collect(Collectors.groupingBy(MyObj::getID)) .entrySet() .stream() // 对每个ID组筛选版本最高的对象 .map(entry -> entry.getValue().stream() .max(Comparator.comparing(obj -> Version.parse(obj.getVersion()))) .orElse(null)) .filter(obj -> obj != null) .collect(Collectors.toList()); // 输出结果:[MyObj{ID='bike', version='2.0'}, MyObj{ID='car', version='4.6'}] System.out.println(result); } }
方案2:自定义版本比较器(兼容Java 8)
如果必须用Java 8,自定义版本字符串的比较逻辑,拆分版本号数字段逐一对比:
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { MyObj obj1 = new MyObj("bike", "1.8"); MyObj obj2 = new MyObj("bike", "2.0"); MyObj obj3 = new MyObj("car", "3.4"); MyObj obj4 = new MyObj("car", "4.6"); List<MyObj> list = new ArrayList<>(); list.add(obj1); list.add(obj2); list.add(obj3); list.add(obj4); // 自定义版本比较器 Comparator<MyObj> versionComparator = (objA, objB) -> { String[] v1 = objA.getVersion().split("\\."); String[] v2 = objB.getVersion().split("\\."); int minLength = Math.min(v1.length, v2.length); for (int i = 0; i < minLength; i++) { int num1 = Integer.parseInt(v1[i]); int num2 = Integer.parseInt(v2[i]); if (num1 != num2) { return Integer.compare(num1, num2); } } // 前缀相同时,段数多的版本更高(如1.2.1 > 1.2) return Integer.compare(v1.length, v2.length); }; // 核心筛选逻辑 List<MyObj> result = list.stream() .collect(Collectors.groupingBy(MyObj::getID)) .entrySet() .stream() .map(entry -> entry.getValue().stream() .max(versionComparator) .orElse(null)) .filter(obj -> obj != null) .collect(Collectors.toList()); // 输出结果:[MyObj{ID='bike', version='2.0'}, MyObj{ID='car', version='4.6'}] System.out.println(result); } }
逻辑说明
- 分组:通过
groupingBy(MyObj::getID)把列表按ID拆分,每个组对应同一个ID的所有对象。 - 取最大值:对每个分组内的对象,用
max()方法结合版本比较器,选出版本最高的实例。 - 收集结果:将所有分组的最高版本对象汇总成最终列表。
内容的提问来源于stack exchange,提问作者JavaLearner
相关产品推荐
相关产品推荐

