Java Stream复杂过滤问题咨询:筛选街道含指定字符的Person
嘿,这事儿用Java Stream完全能搞定,思路和你之前用的SQL内连接其实异曲同工,我给你拆解清楚哈!
首先得先明确下POJO的结构(你没给出具体定义,我先按最常见的两种场景来演示):
场景1:Person与Address通过外键关联(对应SQL内连接的场景)
这种情况和你用SQL JOIN的逻辑最像——两个集合分别存Person和Address,Person里用addressId关联Address的id。
先定义POJO
// Person类 public class Person { private Long id; private String name; private Long addressId; // 关联Address的主键id // 构造器、getter、toString方法这里就省略啦 } // Address类 public class Address { private Long id; private String street; private String city; // 构造器、getter、toString方法同样省略 }
模拟测试数据
import java.util.Arrays; import java.util.List; List<Person> personList = Arrays.asList( new Person(1L, "Alice", 1L), new Person(2L, "Bob", 2L), new Person(3L, "Charlie", 3L), new Person(4L, "David", 4L) ); List<Address> addressList = Arrays.asList( new Address(1L, "Main Street", "New York"), new Address(2L, "Oak Avenue", "London"), // 街道含"ol" new Address(3L, "Maple Road", "Paris"), new Address(4L, "Coral Lane", "Tokyo") // 街道含"ol" );
Stream实现方案
方案1:直接遍历匹配(小数据量友好)
这个写法最直观,直接在filter里判断当前Person对应的Address是否符合街道包含"ol"的条件:
import java.util.stream.Collectors; List<Person> filteredPersons = personList.stream() .filter(person -> addressList.stream() // 先匹配关联的Address,再筛选街道条件 .anyMatch(address -> address.getId().equals(person.getAddressId()) && address.getStreet().contains("ol"))) .collect(Collectors.toList());
方案2:用Map预处理(大数据量更高效)
如果你的集合数据量比较大,每次遍历addressList会有点慢,建议先把Address转成以id为key的Map,这样查找关联Address的效率会高很多:
import java.util.Map; import java.util.Objects; import java.util.AbstractMap; import java.util.stream.Collectors; // 先把Address集合转成Map,key是addressId,value是Address对象 Map<Long, Address> addressMap = addressList.stream() .collect(Collectors.toMap(Address::getId, address -> address)); List<Person> filteredPersons = personList.stream() // 把Person和对应的Address配对成Entry,没有对应Address的就设为null .map(person -> { Address address = addressMap.get(person.getAddressId()); return address != null ? new AbstractMap.SimpleEntry<>(person, address) : null; }) .filter(Objects::nonNull) // 过滤掉没有对应Address的Person(对应SQL内连接的逻辑) .filter(entry -> entry.getValue().getStreet().contains("ol")) // 筛选街道含"ol"的记录 .map(AbstractMap.SimpleEntry::getKey) // 只保留Person对象 .collect(Collectors.toList());
场景2:Person直接持有Address对象
如果你的Person类里直接包含Address属性(而不是外键),那代码会更简洁:
调整后的Person类
public class Person { private Long id; private String name; private Address address; // 直接持有Address对象 // 构造器、getter、toString省略 }
Stream筛选代码
import java.util.stream.Collectors; List<Person> filteredPersons = personList.stream() // 先判断Address不为空,再筛选街道包含"ol" .filter(person -> person.getAddress() != null && person.getAddress().getStreet().contains("ol")) .collect(Collectors.toList());
核心思路其实就是:先把Person和对应的Address关联起来(对应SQL的JOIN操作),然后筛选出符合街道条件的记录,最后收集Person对象就好啦!
内容的提问来源于stack exchange,提问作者David Tavan
相关产品推荐
相关产品推荐

