我试图使用Java 8流在LinkedList中查找元素。但是,我想保证与筛选条件有且只有一个匹配。
以这段代码为例:
public static void main(String[] args) {
LinkedList<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));
User match = users.stream().filter((user) -> user.getId() == 1).findAny().get();
System.out.println(match.toString());
}
static class User {
@Override
public String toString() {
return id + " - " + username;
}
int id;
String username;
public User() {
}
public User(int id, String username) {
this.id = id;
this.username = username;
}
public void setUsername(String username) {
this.username = username;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public int getId() {
return id;
}
}
这段代码根据用户的ID查找用户。但是不能保证有多少用户匹配过滤器。
更改过滤器行为:
User match = users.stream().filter((user) -> user.getId() < 0).findAny().get();
将抛出一个NoSuchElementException(很好!)
但是,如果有多个匹配,我希望它抛出一个错误。有办法做到这一点吗?
收藏家。toMap(keyMapper, valueMapper)使用抛出合并来处理具有相同键的多个条目,这很简单:
List<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));
int id = 1;
User match = Optional.ofNullable(users.stream()
.filter(user -> user.getId() == id)
.collect(Collectors.toMap(User::getId, Function.identity()))
.get(id)).get();
对于重复的键,您将得到一个IllegalStateException。但在最后,我不确定如果使用if,代码是否会更可读。
如果你不使用Guava或Kotlin,这里有一个基于@skiwi和@Neuron答案的解决方案。
users.stream().collect(single(user -> user.getId() == 1));
or
users.stream().collect(optional(user -> user.getId() == 1));
其中single和optional是返回相应收集器的静态导入函数。
我认为,如果将过滤逻辑移到收集器内部,看起来会更简洁。同样,如果您碰巧用.filter删除字符串,代码中也不会中断任何内容。
代码https://gist.github.com/overpas/ccc39b75f17a1c65682c071045c1a079的要点
Guava提供了MoreCollectors.onlyElement(),它在这里做正确的事情。但如果你必须自己做,你可以为这个创建自己的Collector:
<E> Collector<E, ?, Optional<E>> getOnly() {
return Collector.of(
AtomicReference::new,
(ref, e) -> {
if (!ref.compareAndSet(null, e)) {
throw new IllegalArgumentException("Multiple values");
}
},
(ref1, ref2) -> {
if (ref1.get() == null) {
return ref2;
} else if (ref2.get() != null) {
throw new IllegalArgumentException("Multiple values");
} else {
return ref1;
}
},
ref -> Optional.ofNullable(ref.get()),
Collector.Characteristics.UNORDERED);
}
…或者使用你自己的Holder类型而不是AtomicReference。您可以尽可能多地重用收集器。