2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Setに無ければ追加、あればエラーメッセージ

Last updated at Posted at 2018-04-12

例えば、「何かのリストなどからランダムに選び、すでに選んだものをSetに入れる」ということをする場合、
「選んだものがSetに無ければ追加、あればエラーメッセージなどの処理を行う」というのは割とありそう。
これは直感的には

無ければ追加、あればエラー
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 10; i++){
    int r = (int)(Math.random() * 10);
    if (!set.contains(r)) {
        set.add(r);
    } else {
        System.out.println(r + "はすでに入っている");
    }
}

このように、入れる前にcontainsで調べる、と書きたくなる。
しかし、実はこんな書き方もできる。

追加できなかったらエラー
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 10; i++){
    int r = (int)(Math.random() * 10);
    if (!set.add(r)) {
        System.out.println(r + "はすでに入っている");
    }
}

入っているかどうかを事前にチェックせず、いきなりaddし、それをifに入れることができるのである。

実はあまり日の目を見ることはないが、SetをはじめとするCollectionインタフェースのaddメソッドはbooleanを返す。
内容を見ると、

指定された要素がこのコレクションに格納されていることを保証します(オプションの操作)。この呼出しの結果、コレクションが変更された場合はtrueを返します。このコレクションが要素の重複を許可せず、指定された要素がすでに含まれている場合はfalseを返します。

addは「追加する」メソッドではなく、「その要素があることを保証する」メソッドであり、その前後でコレクションが変わったかどうかの結果を返す。
Setの場合は入れようとした要素がすでにある場合は追加しない。つまりSetが変更されることはないため、falseを返す。これがそのまま「入っていたかどうか」の判定に使えるわけだ。同時に、無かった場合はすでに追加を完了しているため、「無かった場合」に追加する処理を改めて書く必要がなくなる。

とはいえ

直感的に読みにくいコードであることには違いないだろう。Set以外にこのCollection#addの性質を活かせる場面はあるのだろうか…?

2
0
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?