Java ストリームを 1 つの要素のみにフィルタリングする 質問する

Java ストリームを 1 つの要素のみにフィルタリングする 質問する

Java 8を使用しようとしていますStreams を使用して 内の要素を検索しますLinkedList。ただし、フィルター条件に一致するものが 1 つだけであることを保証する必要があります。

次のコードを見てください:

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

このコードは、UserID に基づいて を検索します。ただし、Userフィルターに一致する の数については保証されません。

フィルター ラインを次のように変更します。

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

投げますよNoSuchElementException(良い!)

ただし、複数の一致がある場合はエラーをスローするようにしたいと思います。これを行う方法はありますか?

ベストアンサー1

カスタムを作成する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);
            }
    );
}

を使用しておりますCollectors.collectingAndThen私たちの望みを叶えるためCollector

  1. Listコレクターと一緒にオブジェクトを収集しますCollectors.toList()
  2. 最後に追加のフィニッシャーを適用して、単一の要素を返すか、IllegalStateExceptionifをスローしますlist.size != 1

使用されます:

User resultUser = users.stream()
        .filter(user -> user.getId() > 0)
        .collect(toSingleton());

Collectorその後、コンストラクターで例外を引数として渡したり、2 つの値を許可するように調整するなど、必要に応じてこれをカスタマイズできます。

代わりの(おそらくあまりエレガントではない)解決策:

peek()と を伴う「回避策」を使用することもできますAtomicIntegerが、実際にはこれを使用すべきではありません。

代わりに、次のように に収集することもできますList

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

おすすめ記事