2009-07-02 11 views
3

nullを避けるためにnull /空のオブジェクトを返すことができますが、オブジェクトのようなCollectionはどうでしょうか?ヌルフリーデザインでリスト、セット、およびマップを実装する方法は?

Javaの場合、Mapは、のkeyがマップに見つからない場合、nullを返します。このような状況でnullのを避けるために、私は考えることができる

最良の方法は、どちらかEmptyEntry<T>あるEntry<T>オブジェクトを、返すことである、または値Tが含まれています。

確かにnullは避けますが、EmptyEntry<T>をチェックしないと、クラスキャストの例外が発生することがあります。

nullは、Mapget(K)にはありませんか?

そして、議論のために、この言語にはnullも含まれていないとしましょう。nullsを使用しないでください。

+0

@Sanoj awですが、私は常に宇宙飛行士になりたがっています – Pyrolistical

答えて

1

例外をスローします。例としては、.NETのKeyNotFoundException、JavaのArrayIndexOutOfBoundsException、PythonのKeyErrorなどがあります。

例外は例外的な状況であることを知っているので、ユーザーは、キーを探し出す前にそのキーが存在することを確認する必要があります。

グッド

if collection.contains(key): 
    return collection.get(key); 

悪い

try: 
    return collection.get(key); 
catch KeyError: 
    pass # Don't care. 
+1

Tomの権利:例外的でない場合の例外を捕まえなければならないのは遅いです。 –

+0

あなたの良い例と悪い例は状況に大きく左右されます。キーが最初に存在するかどうかをチェックするかどうかの選択は、多くのことに依存します。たとえば、次の場合は最初にチェックしたくない場合があります。 - スピードのためにタイトなループを最適化しています。 - キーが存在しないことは稀です(鍵の数が限られています) – RHSeeger

+1

私は私の提案を繰り返してください:TryGetのようなものが理想的でしょう。 –

2

あなたは "要素が存在しないexcepton" を投げることができますが、例外は高価であり、 "例外的な状況" のために確保されなければなりません。地図に表示されていない値はほとんどありませんので、スピードバンプかもしれませんが、いつものように、現在の状況によって異なります。

いずれにしても、アドバイスとして、 (key)メソッドを含んでいます。キーがnull値にマッピングされているということは常にposiblityなので、get(key)はマップにあってもnullを返します。

編集:ここでは完全にテストされていないと、現在の時刻が1時08分AMである、と私はひどい風邪をひいている!!:

のget()のソースコードを見た後、私は記録のために(何かを思い付きました)

314  public V get(Object key) { 
    315   if (key == null) 
    316    return getForNullKey(); 
    317   int hash = hash(key.hashCode()); 
    318   for (Entry<K,V> e = table[indexFor(hash, table.length)]; 
    319    e != null; 
    320    e = e.next) { 
    321    Object k; 
    322    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 
    323     return e.value; 
    324   } 
       //This could be instanced by reflection (bad idea?) 
    325   return new MappeableElementImpl(); 
    } 

あなたがそのようないくつかのMappeableElementとしてインターフェイスまたはメソッドブールisUnmappedValueを(持っていたようなもの)を実装するためにVを強制することができ、私は、get()メソッドは、そのインターフェイスのインスタンスを返すことができます。

Element e = map.get(notpresentkey); 

if (e.isUnmappedValue()){sysout (notpresentkey +" is not present");} 
+0

これはヌルの状況をどのように改善していますか?なぜなら、地獄は確かに同じ結果を私に得る複雑な方法のように見えるからです... –

5

2つの解決策:

だから、のようなものに終わるだろう

  1. は(キー)関数が含まれて提供します。存在しないキーに対してget(key)が呼び出された場合は例外をスローします。欠点は、contains()の後にget()を呼び出すことです。効率的ではありません。

  2. 機能的言語は、おそらく同様の状況で使用します。この資料では、how to implement Maybe in Javaについて説明します。

+1

Containsの呼び出しがGetと同じことをするので、これは遅くなります。したがって、tryGetオプションは –

+0

です。出力は1.見つかったかどうか2.結果が見つかった場合 –

+0

@スティーブン - 私の意見に感謝します。私の答えを更新しました。 –

1

generic Optional<T>タイプのインスタンスを返します。

0

見つかった項目があるか、または例外がスローされた項目に対して、ブール値を持つオブジェクトを返すことができるとします。別の方法は、TryGet技術を使用することです。

1

私はそれを見ると3つの可能性があります。

  • nullまたはNullオブジェクトを返します。
  • 例外をスローしてキャッチします。
  • getに電話する前に、containsKeyに電話して問題を回避してください。あなたは(のように扱っている何のための正しい種類の特殊なヌルオブジェクトを作成し、あなたはヌルオブジェクトが間違った型であることについて心配している場合は、あなたがNullObjectFactoryを受け入れるようにマップを設計でき

Null Object pattern)。そうすれば、nullを返すかどうかをチェックすることなく、キーが含まれているかどうかをチェックせずに、例外をキャッチする必要なく、マップからgetを得ることができます。

0

あなたはnullの代替手段を探していることを理解していますが、代替案はすべてnullのテストよりもはるかに高価な(スタックトレースなどを生成する)いくつかの例外ケースを引き起こすようです。

無効な(つまりヌル)値を挿入しようとしたとき、または不正なget()にNoValuePresentExceptionを返そうとしたときに、InvalidValueExceptionを返します。 (あなたが行うことができる単純なヌルテストがあったら嬉しいです)

2

設計しているデータ構造が珍しい必要条件やシナリオのためにあなたの疑問がおありですか?後者の場合、nullは他の参照値と概念的に区別できないという事実を考慮したいかもしれません(例えば、nullを示すいくつかの最終的なobjを参照)、例外は高価です。あなたがこの質問をする特定の懸念や目標を持っていない限り、あなたは本当に私たちの時間を無駄にしています。乾杯!

+1

'' null'を持たない(または少なくとも使用を避ける)システムを設計することは、非常に有益です。理論的な思考実験ではありません。例えば、ヌルオブジェクトパターンを参照してください:http://en.wikipedia.org/wiki/Null_Object_pattern –

0

概念的には大きな問題です。便利なシナリオの1つは、すべての呼び出しを基礎となるマップオブジェクトに委譲するアダプタを作成することです。このアダプタには、nullオブジェクトを指定する必須パラメータがあります。たとえば、

class MapAdapter<K,V> implements Map<K,V> { 
    private Map<K,V> inner = new HashMap<K,V>(); 
    private final V nullObject; 

    private MapAdapter(V nullObject) { 
     this.nullObject = nullObject; 
    } 

    public static <K,V> Map<K,V> adapt(Map<K,V> mapToAdapt, V nullObject) { 
     MapAdapter<K,V> adapter = new MapAdapter<K,V>(nullObject); 
     adapter.inner.addAll(mapToAdapt); 
     return adapter; 
    } 


    //Here comes implementation of methods delegating to inner. 


    public V get(K key) { 
     if (inner.containsKey(key)) { 
      return inner.get(key); 
     } 
     return nullObject; 
    } 
} 

一般的なNullSafeの実装が可能ですが、

1

Cf.上の@Doug McClean - これはScalaがOptionと呼んでいるように聞こえ、HaskellはMaybeと呼んでいます。それはあなたがEntryEmptyEntryと、説明したもののように多くのです - ScalaはEmptyEntryのために有効なEntryのためSomeNoneを使用しています。

Daniel Spiewakには、基本的なJava実装を含むa good intro to Optionがあります。 (彼のinstanceof Noneチェックの代わりにisNone()メソッドがあり、実行時にJavaジェネリックが消去されるため実際には何も含まれていないので、キャストするか、それをキャストする「ファクトリ」メソッドは、None<T>が必要です)。

0

これはたぶん、オプションのようです。

パターンマッチングは、このクラスのユーザーにとってより簡単にするためにも必要です。このようにして、ユーザーはinstanceofを使用してリアルタイムのクラスキャスト例外の危険でキャストする必要はありません。

+0

その場合、 'Map'をまったく実装しない方が良いかもしれません - 代わりに、マップのようなインタフェースを実装してあなたは 'get()'の代わりに、キーとバリューハンドラを渡し、同様に反復を行います。 –

+0

@David:すべての敬意を払って、その種のデリゲートベースの回答はTryGetよりも複雑で遅いです。 –

+0

@スティーブンスディット:あなたは詳しく述べることができますか?私はパフォーマンスが最悪であると予想しますが、おそらく私はあなたのtryGet()アプローチを誤解しています。それは私にはもっと複雑に見えませんが、それはもっと機能的なプログラミングスタイルに慣れているからかもしれません。 –

関連する問題