62

座標間の距離に基づいて住所のリストをソートするコードがあります。これは、カスタム コンパレータを使用して collections.sort を介して行われます。

ただし、座標のない住所がリストに含まれていると、NullPointerException が発生することがあります。これを修正するための最初のアイデアは、少なくとも 1 つの座標が null である住所の距離としてコンパレーターが 0 を返すようにすることでした。これにより、リスト内の「有効な」要素の順序が崩れる可能性があるのではないかと心配しています。

コンパレーターの null データに対して '0' 値を返すのは問題ありませんか、それともこれを解決するよりクリーンな方法はありますか?

4

10 に答える 10

88

null無限に遠いという意味のように扱います。したがって:

  • comp(1234, null) == -1
  • comp(null, null) == 0
  • comp(null, 1234) == 1

これにより、一貫した順序が得られます。

于 2010-03-08T13:39:05.563 に答える
26

WilliSchönbornの答えを拡張するために、私はここに来て、google-collectionsはまさにあなたがここで求めているものだと言いました。

一般的なケースでは、nullを無視するように独自に記述してComparator(null以外を想定しているため、重要なロジックに集中できます)、Orderingを使用してnullを処理できます。

Collections.sort(addresses, Ordering.from(new AddressComparator()).nullsLast());

ただし、あなたの場合、並べ替えに使用されているのはアドレス(座標)内のデータですよね?この場合、 google-collectionsはさらに便利です。したがって、次のようなものがある可能性があります。

// Seems verbose at first glance, but you'll probably find yourself reusing 
// this a lot and it will pay off quickly.
private static final Function<Address, Coordinates> ADDRESS_TO_COORDINATES = 
  new Function<Address, Coordinates>() {
      public Coordinates apply(Address in) {
          return in.getCoordinates();
      }
  };

private static final Comparator<Coordinates> COORDINATE_SORTER = .... // existing

次に、並べ替える場合:

Collections.sort(addresses,
    Ordering.from(COORDINATE_SORTER)
            .nullsLast()
            .onResultOf(ADDRESS_TO_COORDINATES));

そして、それがgoogle-collectionsの力が実際に報われ始めるところです。

于 2010-03-08T23:03:27.177 に答える
10

これについての私の見解は、座標を「良くする」ためにあなたがしようとすることnullは、ただ亀裂を紙で覆っているだけだということです。あなたが本当にする必要があるのは、偽のnull座標を注入しているバグを見つけて修正することです。

私の経験では、NPEバグの蔓延は、次の悪いコーディング習慣によって引き起こされることがよくあります。

  • 入力パラメータの不十分な検証、
  • null空の配列またはコレクションの作成を回避するために使用する、
  • null例外がスローされるべきときに戻る、または
  • nullより良い解決策がある場合に「値なし」を表すために使用します。

(「値なし」の問題に対するより良い解決策は、通常、コードを書き直して、これを表す必要がないようにするか、代わりにnull以外の値を使用することです。たとえば、空の文字列、特別なインスタンス、予約済みの値などです。常により良い解決策を見つけるとは限りませんが、多くの場合は可能です。)

nullこれがアプリケーションを説明している場合は、値が発生するNPEを回避する方法を考えるのではなく、値を挿入しているコードの問題を見つけて修正することに時間を費やす必要があります。

于 2010-03-08T14:04:57.757 に答える
9

私の解決策 (ここを見ている人にとっては役立つかもしれません) は、null 値を 0 ではなく、可能な最大値 (Integer.MAX_VALUE など) に置き換えて、通常の比較を行うことです。値自体が 0 の場合、0 を返すことは一貫していません。正しい例を次に示します。

        public int compare(YourObject lhs, YourObject rhs) {
            Integer l = Integer.MAX_VALUE;
            Integer r = Integer.MAX_VALUE;
            if (lhs != null) {
                l = lhs.giveMeSomeMeasure();
            }
            if (rhs != null) {
                r = rhs.giveMeSomeMeasure();
            }
            return l.compareTo(r);
        }

整数の最大値は必要ないことを付け加えたいと思います。それは、あなたの giveMeSomeMeasure() メソッドが何を返すことができるかによって異なります。たとえば、天気の摂氏度を比較する場合、null オブジェクトを設定する場所 (リストの先頭または末尾) に応じて、l と r を -300 または +300 に設定できます。

于 2012-03-09T10:29:23.727 に答える
3

アドレスが等距離であり、本当にわからないことを意味するため、おそらく 0 を返したくないでしょう。これは、不適切な入力データを処理しようとする場合の非常に古典的な問題です。距離がわからない場合に、住所が実際にどのくらい離れているかを判断しようとするのは、コンパレーターの責任だとは思いません。並べ替える前に、これらのアドレスをリストから削除します。

ハックは、それらをリストの一番下に移動することです(しかし、それは醜いです!)

于 2010-03-08T13:41:38.973 に答える
1

これをコンパレータの技術的な問題のように見るのではなく、要件をもう一度確認することをお勧めします。ここで実際に何をしようとしているのか、このソートされたリストで何をするのか。

  • ユーザーに最も関連性の高いソリューションを最初に表示するように並べ替える場合は、不明な場所を最後に配置することをお勧めします。そのため、無限のように扱います(どちらが0 / -1 /1であるかによって返されます)。ヌル)。
  • この結果を使用してグラフを描画したり、実際に距離で並べ替えられていることに依存する他の計算を実行したりする場合は、ヌルがそこにあるべきではない可能性があります(したがって、最初にヌルを削除するか、その時点で、場所がnullのアドレスが実際に存在しないはずだった場合は例外です)。

すでにご存知のように、そのうちの1つがnullのときに常に0を返すことは、ここではお勧めできません。それは確かに結果を損なう可能性があります。しかし、代わりに何をすべきかは、他の人が通常行う/必要とすることではなく、あなたが必要とするものに依存します。場所がないアドレスでプログラムがどのように動作するか(つまり、ユーザーに表示される内容)は、コンパレータの「ベストプラクティス」などの技術的な詳細に依存するべきではありません。(私にとって、ここでの「ベストプラクティス」とは何かを尋ねるのは、「ベスト要件」とは何かを尋ねるようなものです)。

于 2010-03-08T14:03:56.963 に答える
1

私は個人的に、コンパレーターのあらゆる場所で特別な null ケースを扱うのが嫌いなので、よりクリーンなソリューションを探していて、最終的に Google コレクションを見つけました。彼らの注文は素晴らしいです。それらは複合コンパレータをサポートし、null を先頭と末尾にソートし、比較する前に特定の関数を実行できるようにします。コンパレータの作成は、これまでになく簡単になりました。試してみてください。

于 2010-03-08T20:24:50.240 に答える
1

いいえ、よりクリーンな方法はありません。多分:

  • 比較された両方のオブジェクトの座標が null の場合、0 を返します
  • いずれかのオブジェクトの座標が null の場合、-1 / 1 を返します (最初の引数か 2 番目の引数かによって異なります)

しかし、もっと重要なことは、欠落している座標を取り除く/埋めるようにすることです。または、より良いのは、リストに欠落している座標のある住所を入れないことです。

実際には、それらをリストに入れないことが最も論理的な動作です。それらをリストに入れると、結果は実際には距離順に並べられません。

座標が欠落しているアドレスを含む別のリストを作成し、その情報が必要な人 (エンドユーザー、API ユーザー) に対して、最初のリストには必要なデータを含むアドレスのみが含まれ、2 番目のリストには必要なデータが含まれているアドレスが含まれていることを明確にすることができます。必要な情報が不足しています。

于 2010-03-08T13:39:02.850 に答える