java stream 多个filter_将Java Stream过滤为1并且只有1个元素

I am trying to use Java 8 Streams to find elements in a LinkedList. I want to guarantee, however, that there is one and only one match to the filter criteria.

Take this code:

public static void main(String[] args) {

LinkedList 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;

}

}

This code finds a User based on their ID. But there are no guarantees how many Users matched the filter.

Changing the filter line to:

User match = users.stream().filter((user) -> user.getId() < 0).findAny().get();

Will throw a NoSuchElementException (good!)

I would like it to throw an error if there are multiple matches, though. Is there a way to do this?

解决方案

Create a custom Collector

public static Collector toSingleton() {

return Collectors.collectingAndThen(

Collectors.toList(),

list -> {

if (list.size() != 1) {

throw new IllegalStateException();

}

return list.get(0);

}

);

}

We use Collectors.collectingAndThen to construct our desired Collector by

Collecting our objects in a List with the Collectors.toList() collector.

Applying an extra finisher at the end, that returns the single element — or throws an IllegalStateException if list.size != 1.

Used as:

User resultUser = users.stream()

.filter(user -> user.getId() > 0)

.collect(toSingleton());

You can then customize this Collector as much as you want, for example give the exception as argument in the constructor, tweak it to allow two values, and more.

An alternative — arguably less elegant — solution:

You can use a 'workaround' that involves peek() and an AtomicInteger, but really you shouldn't be using that.

What you could do istead is just collecting it in a List, like this:

LinkedList users = new LinkedList<>();

users.add(new User(1, "User1"));

users.add(new User(2, "User2"));

users.add(new User(3, "User3"));

List resultUserList = users.stream()

.filter(user -> user.getId() == 1)

.collect(Collectors.toList());

if (resultUserList.size() != 1) {

throw new IllegalStateException();

}

User resultUser = resultUserList.get(0);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值