web-dev-qa-db-ja.com

Guava MapMaker / CacheBuilderを使用してnull値を処理する

MapMaker/CacheBuilderを使用してキャッシュを作成しようとしましたが、null値を適切に処理する方法がわかりません。

 ConcurrentMap<Key, Graph> graphs = new MapMaker()
       .concurrencyLevel(4)
       .weakKeys()
       .maximumSize(10000)
       .expireAfterWrite(10, TimeUnit.MINUTES)
       .makeComputingMap(
           new Function<Key, Graph>() {
             public Graph apply(Key key) {
               return createExpensiveGraph(key);
             }
           });

メソッドcreateExpensiveGraphがnull値を返す場合、NullpointerExceptionがスローされます。 ComputingConcurrentHashMapが単にnull値を返すのではなく、NPEをスローする理由がわかりません。

これを適切に処理する方法は? NPEをキャッチして、代わりにnullを返しますか?私は何かが足りないのですか?

26

Guavaは、nullの存在下での不適切または文書化されていない動作が大量の混乱とバグを引き起こす可能性があるため、可能な限りnullの使用を回避するように強制しようとします。可能な限りnullを使用しないことは間違いなく良い考えだと思います。また、nullを使用しないようにコードを変更できる場合は、代わりにそのアプローチを強くお勧めします。

あなたの質問に対する答えは、アプリケーションで「null」値が実際に何を意味するかによって大きく異なります。ほとんどの場合、このキーには「値がない」、または「そこに何もない」ことを意味します。この場合、おそらく最善の策は Optional を使用し、null以外の値をOptional。ofでラップし、代わりにOptional.absent()を使用することです。 null。これをnullまたはnull以外の値に変換する必要がある場合は、Optional.orNull()を使用できます。

47
Louis Wasserman

あなたの質問の完全なステートメントでさえ、あなたの意図がそのnull値をキャッシュすることであるかどうかがまだ明確でないことに注意してください。 CacheBuilderがnull値をキャッシュすることを決定したかどうかにかかわらず、反対のことを期待していた多くのユーザーを驚かせるでしょう。繰り返しになりますが、nullはあいまいさを生み出します(それが最高です!)。

だからここにあなたがすることです。

  1. createExpensiveGraphの全費用をかけずに、答えが「null」になると判断することは可能ですか?つまり、実際には単純な前提条件チェックが行われているだけですか?もしそうなら、キャッシュを要求する前にそれを行う必要があります。その時点で、結果をキャッシュする必要があるかどうかの問題はなくなります。

  2. Null値をキャッシュしますか?次に、ルイのアドバイスに従ってOptional<T>を使用します。

  3. それ以外の場合、キャッシュはキーの正しい値を呼び出すジョブを実行できず、適切な応答はキャッシュローダーから例外をスローすることです(これがプログラマーエラーの場合はオフ、それ以外の場合はチェック)。そして、それはあなたが望む振る舞いを提供します。チェックされた例外をスローする場合は、反対側でCache.getではなくCache.getUncheckedを使用していることを確認してください。

11

これに対処する方法のいくつかのアイデアについては、Guava wikiの LivingWithNullHostileCollections を参照してください。

9
fry