Java 过滤 Map
上次修改时间:2025 年 6 月 26 日
在本教程中,我们将演示如何使用 Stream API 在 Java 中过滤 Map。过滤 Map 是处理集合时的常见任务,尤其是在需要提取满足特定条件的条目时。
HashMap 是 Java 中广泛使用的数据结构,用于存储键值对。 HashMap 中的每个键都是唯一的,并映射到单个值。 这使其成为快速查找和高效数据检索的理想选择。
要过滤 HashMap,我们可以利用 Java Stream API 提供的 filter 方法。 此方法接受一个谓词——一个函数式接口,它评估每个条目并根据条件返回 true 或 false。 结果是一个新的流,仅包含满足谓词的条目。
例如,您可以过滤 Map 以仅包含值大于某个阈值的条目,或者键与特定模式匹配的条目。 过滤后,可以使用 Collectors.toMap 将流收集回 Map 中。
按值过滤 Map
在第一个例子中,我们过滤 Map 的值。
void main() {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(e -> e.getValue().startsWith("B"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filteredCapitals.entrySet().forEach(System.out::println);
}
我们有一个首都 Map。 我们使用 entrySet 获取 Map 的条目。 然后我们使用 stream 将集合转换为流。
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(e -> e.getValue().startsWith("B"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
我们过滤 Map 以仅包含值以 B 开头的键值对。我们使用 getValue 从当前条目获取值。
$ java Main.java hun=Budapest ger=Berlin svk=Bratislava
按键过滤 Map
在下一个例子中,我们按键过滤 Map。
void main() {
Map<String, String> capitals = new HashMap<>();
capitals.put("svk", "Bratislava");
capitals.put("ger", "Berlin");
capitals.put("hun", "Budapest");
capitals.put("czk", "Prague");
capitals.put("pol", "Warsaw");
capitals.put("ita", "Rome");
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(e -> e.getKey().endsWith("k"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filteredCapitals.entrySet().forEach(System.out::println);
}
该示例过滤所有键以字母 k 结尾的条目。
Map<String, String> filteredCapitals = capitals.entrySet().stream()
.filter(e -> e.getKey().endsWith("k"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
我们使用 getKey 获取条目的当前键。
$ java Main.java czk=Prague svk=Bratislava
按键和值过滤 Map
在下一个例子中,我们按键和值过滤 Map。
void main() {
Map<Integer, String> users = new HashMap<>();
users.put(1, "John Doe");
users.put(2, "Roger Roe");
users.put(3, "Jane Doe");
users.put(4, "Jack Drake");
users.put(5, "Peter Morgan");
users.put(6, "Robert Melnik");
Map<Integer, String> filtered = users.entrySet().stream()
.filter(e -> e.getKey() % 2 == 0)
.filter(e -> e.getValue().split(" ")[1].startsWith("D"))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
filtered.entrySet().forEach(System.out::println);
}
我们有一个用户 Map。 我们过滤掉所有键为偶数且姓氏以字母 D 开头的用户。
$ java Main.java 4=Jack Drake
按年龄过滤
我们有一个用户 Map。 我们按用户的年龄过滤 Map。
void main() {
var dft = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Map<Integer, User> users = new HashMap<>();
users.put(1, new User("John Doe", "gardener", LocalDate.parse("1973-09-07", dft)));
users.put(2, new User("Roger Roe", "driver", LocalDate.parse("1963-03-30", dft)));
users.put(3, new User("Kim Smith", "teacher", LocalDate.parse("1980-05-12", dft)));
users.put(4, new User("Joe Nigel", "artist", LocalDate.parse("1983-03-30", dft)));
users.put(5, new User("Liam Strong", "teacher", LocalDate.parse("2009-03-06", dft)));
users.put(6, new User("Robert Young", "gardener", LocalDate.parse("1978-11-16", dft)));
users.put(7, new User("Liam Strong", "teacher", LocalDate.parse("1986-10-23", dft)));
Map<Integer, User> olderThanForty = users.entrySet().stream().filter(e -> {
LocalDate dob = e.getValue().dob();
int age = Period.between(dob, LocalDate.now()).getYears();
return age > 40;
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
olderThanForty.entrySet().forEach(System.out::println);
}
record User(String name, String occupation, LocalDate dob) {
}
我们过滤掉所有大于 40 岁的用户。
Map<Integer, User> olderThanForty = users.entrySet().stream().filter(e -> {
LocalDate dob = e.getValue().dob();
int age = Period.between(dob, LocalDate.now()).getYears();
return age > 40;
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
我们使用 e.getValue().dob() 从用户对象中检索出生日期。 然后我们使用 Period.between(dob, LocalDate.now()).getYears() 计算用户的年龄。 过滤条件是 age > 40;
$ java Main.java 1=User[name=John Doe, occupation=gardener, dob=1973-09-07] 2=User[name=Roger Roe, occupation=driver, dob=1963-03-30] 3=User[name=Kim Smith, occupation=teacher, dob=1980-05-12] 6=User[name=Robert Young, occupation=gardener, dob=1978-11-16]
使用逻辑运算符按多个条件过滤
在此示例中,我们将演示如何使用逻辑运算符(如 AND (&&) 和 OR (||))组合的多个条件来过滤 Map。
void main() {
Map<String, Product> products = new HashMap<>();
products.put("P001", new Product("Laptop", 899.99, "Electronics", 15));
products.put("P002", new Product("Coffee Mug", 12.99, "Kitchen", 50));
products.put("P003", new Product("Smartphone", 599.99, "Electronics", 8));
products.put("P004", new Product("Book", 19.99, "Education", 25));
products.put("P005", new Product("Headphones", 149.99, "Electronics", 30));
products.put("P006", new Product("Desk Chair", 249.99, "Furniture", 5));
// Filter using AND: Electronics products with price less than 700
Map<String, Product> electronicsCheap = products.entrySet().stream()
.filter(e -> e.getValue().category().equals("Electronics") &&
e.getValue().price() < 700)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println("Electronics products under $700:");
electronicsCheap.entrySet().forEach(System.out::println);
// Filter using OR: Products that are either expensive (>200) or low stock (<10)
Map<String, Product> expensiveOrLowStock = products.entrySet().stream()
.filter(e -> e.getValue().price() > 200 || e.getValue().stock() < 10)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println("\nProducts that are expensive (>$200) or low stock (<10):");
expensiveOrLowStock.entrySet().forEach(System.out::println);
// Complex condition: (Electronics AND expensive) OR (low stock)
Map<String, Product> complexFilter = products.entrySet().stream()
.filter(e -> (e.getValue().category().equals("Electronics") &&
e.getValue().price() > 500) ||
e.getValue().stock() < 10)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println("\nExpensive Electronics OR low stock products:");
complexFilter.entrySet().forEach(System.out::println);
}
record Product(String name, double price, String category, int stock) {
}
此示例显示了使用逻辑运算符的三种不同的过滤场景
- AND 条件:既是电子产品又是 700 美元以下的商品
- OR 条件:要么昂贵(超过 200 美元),要么库存较低(低于 10 件)的商品
- 复杂条件:昂贵的电子产品或任何库存较低的产品
过滤是使用 Java Stream API 的 filter 方法完成的,该方法允许我们为 Map 中的每个条目指定条件。 使用 collect(Collectors.toMap(...)) 将结果收集到新的 Map 中。
$ java Main.java Electronics products under $700: P005=Product[name=Headphones, price=149.99, category=Electronics, stock=30] P003=Product[name=Smartphone, price=599.99, category=Electronics, stock=8] Products that are expensive (>$200) or low stock (<10): P006=Product[name=Desk Chair, price=249.99, category=Furniture, stock=5] P001=Product[name=Laptop, price=899.99, category=Electronics, stock=15] P003=Product[name=Smartphone, price=599.99, category=Electronics, stock=8] Expensive Electronics OR low stock products: P006=Product[name=Desk Chair, price=249.99, category=Furniture, stock=5] P001=Product[name=Laptop, price=899.99, category=Electronics, stock=15] P003=Product[name=Smartphone, price=599.99, category=Electronics, stock=8]
来源
在本文中,我们展示了如何在 Java 中过滤 Map。
作者
列出所有Java教程。