0 votes
1 view
in Java by (3.5k points)

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<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 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?

1 Answer

0 votes
by (46.1k points)

Create a custom Collector

public static <T> Collector<T, ?, T> 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

  1. Collecting our objects in a List with the Collectors.toList() collector.
  2. 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.

Related questions

0 votes
1 answer
0 votes
1 answer
0 votes
1 answer
0 votes
1 answer
0 votes
1 answer
Welcome to Intellipaat Community. Get your technical queries answered by top developers !


Categories

...