lambda - Filter Java Stream to 1 and only 1 element -
i trying use java 8 stream
s find elements in linkedlist
. want guarantee, however, there 1 , 1 match filter criteria.
take code:
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; } }
this code finds user
based on id. there no guarantees how many user
s matched filter.
changing filter line to:
user match = users.stream().filter((user) -> user.getid() < 0).findany().get();
will throw nosuchelementexception
(good!)
i throw error if there multiple matches, though. there way this?
technically there's ugly 'workaround' involves peek()
, atomicinteger
, shouldn't using that.
what in these cases collecting in list, this:
linkedlist<user> users = new linkedlist<>(); users.add(new user(1, "user1")); users.add(new user(2, "user2")); users.add(new user(3, "user3")); list<user> resultuserlist = users.stream() .filter(user -> user.getid() == 1) .collect(collectors.tolist()); if (resultuserlist.size() != 1) { throw new illegalstateexception(); } user resultuser = resultuserlist.get(0);
i not aware of way in api, meanwhile work on example involving custom element.
update, should create own collector
this:
public static <t> collector<t, list<t>, t> singletoncollector() { return collector.of( arraylist::new, list::add, (left, right) -> { left.addall(right); return left; }, list -> { if (list.size() != 1) { throw new illegalstateexception(); } return list.get(0); } ); }
what is:
- it mimicks
collectors.tolist()
collector. - it applies finisher @ end, throws exception, or if no exception, returns first element of list.
used as:
user resultuser = users.stream() .filter(user -> user.getid() > 0) .collect(singletoncollector());
you can customize singletoncollector
as want, example give exception argument in constructor, tweak allow 2 values, , more.
new update, revised old answer once more singletoncollector()
, can obtained this:
public static <t> collector<t, ?, t> singletoncollector() { return collectors.collectingandthen( collectors.tolist(), list -> { if (list.size() != 1) { throw new illegalstateexception(); } return list.get(0); } ); }
Comments
Post a Comment