2008-09-24 17 views
20

Javaでは、いくつかのフィールドをnullにすることができるクラスを使用します。たとえば:compare()のnullフィールドをどうすればいいですか?

class Foo { 
    String bar; 
    //.... 
} 

私はこのクラスのBarComparatorを書きたい、

private static class BarComparator 
      implements Comparator<Foo> { 
     public int compare(final Foo o1, final Foo o2) 
     { 
      // Implementation goes here 
     } 
    } 

o1のいずれか、o2o1.baro2.barをすることができるという事実に対処するための標準的な方法はありますnull 、たくさんのネストを書くことなくif ... else

乾杯!

答えて

36

私はあなたが高いか低いヌルをソートするために、小さな静的メソッドとフィールドcompareToメソッドの呼び出しをラップすることができると思います:

static <T extends Comparable<T>> int cp(T a, T b) { 
    return 
     a==null ? 
     (b==null ? 0 : Integer.MIN_VALUE) : 
     (b==null ? Integer.MAX_VALUE : a.compareTo(b)); 
} 

シンプルな使用方法(複数のフィールド通常どおりです):

public int compare(final Foo o1, final Foo o2) { 
    return cp(o1.field, o2.field); 
} 
+1

オフトピックですが、MIN/MAX_VALUEよりも/ - 1を優先させる理由は何ですか? –

+6

応答が遅れて申し訳ありません。これは、三角不等式を確実にするためです。 a> b> cの場合、a.compareTo(b)+ b.compareTo(c)<= a.compareTo(c)。誰も気にしないでしょう... –

+0

o1/o2がnullの場合でも、依然として 'NullPointerException'を投げることができます。あなたはo1/o2をnullと扱うべきですか? OPの記載:o1、o2、o1.bar、o2.barはnullでもかまいません。あるいは、コンパレータ契約の一部です:ヌルを比較するとNPEを投げるべきですか? – Daniel

1

私にはそれを行う方法はないようですが、とにかくコードはあまり長くありません。

0

私は早期返品陳述がたくさんのifsの代わりになると思います。

if(o1==null) return x; 
if(o2==null) return x; 
if(o1.getBar()==null) return x; 
if(o2.getBar()==null) return x; 

// No null checks needed from this point. 
6

nullエントリが有効な文字列値であるとみなすかどうかによって異なります。 null <または> "apple"です。私が確かに言うことができる唯一のことはnull == nullです。順序がnullになる場所を定義できる場合は、コードを適切に記述することができます。私はNullPointerExcpetionか、IllegalArgumentExceptionをスローし、最初の場所で比較して、それを入れていないことにより、より高いレベルでのヌルを処理しようとすることを選択するかもしれない。この場合

+0

私はこの答えが好きです。ありがとう! – Burkhard

2

ここで重要なことは、nullsをどのように扱うかを考え出すことです。いくつかのオプションは次のとおりです。a)他のすべてのオブジェクトの前にソート順で来ると仮定します。b)他のすべてのオブジェクトの後にソート順でヌルがあると仮定します。どちらを選択するかは、あなたが取り組んでいるアプリケーションに完全に依存します。

最後のケースでは、例外がスローされます。他の場合は、4ウェイのif/elseケースが必要です(結果を得たいものをコーディングした3分のコーディング)。

2

Googleのコレクションを使用している場合は、Comparatorsクラスが役立つことがあります。 Ifには、コレクション内の最大要素または最小要素のいずれかとしてnullを順序付けるヘルパーメソッドがあります。 compound comparatorsを使用すると、コードの量を減らすことができます。

8

返信いただきありがとうございます!ジェネリックメソッドとGoogle Comparatorsは面白く見えます。

そして、私は(我々が現在使用している)Apache Commons CollectionsNullComparatorがあることが見つかりました:

private static class BarComparator 
     implements Comparator<Foo> 
{ 
    public int compare(final Foo o1, final Foo o2) 
    { 
     // o1.bar & o2.bar nulleness is taken care of by the NullComparator. 
     // Easy to extend to more fields. 
     return NULL_COMPARATOR.compare(o1.bar, o2.bar); 
    } 

    private final static NullComparator NULL_COMPARATOR = 
              new NullComparator(false); 
} 

注:私はポイントにそれを維持するためにここにbar分野に焦点を当てました。

+1

Javadocsへのリンクが死んでいるようです。現在はhttp://commons.apache.org/proper/commons-collections/javadocs/api-release/index.htmlにあります。 – JBert

1

あなたはNullComparatorを使用するべきではありません。比較操作ごとにクラスの新しいインスタンスを作成しています。あなたは1000のエントリを持つリストをソートしています。それは1000 * log2(1000)のオブジェクトで完全に余分です。これはすぐに問題になることがあります。

どちらかそれをサブクラス、またはそれに委譲、または単にあなた自身のnullチェックを実装する - それは本当に複雑ではありません。

private static class BarComparator 
     implements Comparator<Foo> { 
    private NullComparator delegate = new NullComparator(false); 

    public int compare(final Foo o1, final Foo o2) 
    { 
     return delegate.compare(o1.bar, o2.bar); 
    } 
} 
+0

そうです、NullComparatorはプライベートな静的フィールドでなければなりません。この例では、無駄に焦点を当てるように書きました。 –

3

あなたはそれのためにあなたのコンパレータを書くことができます。 PersonフィールドにPersonという文字列名を持つクラスがあるとします。 getName()およびsetName()メソッドを使用してフィールド名にアクセスします。以下はPersonクラスのComparatorです。

Collections.sort(list, new Comparator<Person>() { 
     @Override 
     public int compare(Person a, Person b) { 
      if (a == null) { 
       if (b == null) { 
        return 0; 
       } 
       return -1; 
      } else if (b == null) { 
       return 1; 
      } 
      return a.getName().compareTo(b.getName()); 
     } 
    }); 

更新:あなたがリストのためのAPIの下に使用できるJava 8のよう

// Push nulls at the end of List 
Collections.sort(subjects1, Comparator.nullsLast(String::compareTo)); 

// Push nulls at the beginning of List 
Collections.sort(subjects1, Comparator.nullsFirst(String::compareTo)); 
2

クラスorg.springframework.util.comparator.NullSafeComparatorには、使用可能なSpringフレームワークでもあります。

例(Javaの8):

SortedSet<Foo> foos = new TreeSet<>((o1, o2) -> { 
     return new NullSafeComparator<>(String::compareTo, true).compare(o1.getBar(), o2.getBar()); 
    }); 

    foos.add(new Foo(null)); 
    foos.add(new Foo("zzz")); 
    foos.add(new Foo("aaa")); 

    foos.stream().forEach(System.out::println); 

これを印刷します:POJO.Myの答えとしてお客様を考慮

Foo{bar='null'} 
Foo{bar='aaa'} 
Foo{bar='zzz'} 
0

は次のようになります。

Comparator<Customer> compareCustomer = Comparator.nullsLast((c1,c2) -> c1.getCustomerId().compareTo(c2.getCustomerId())); 

それとも

Comparator<Customer> compareByName = Comparator.comparing(Customer::getName,nullsLast(String::compareTo)); 
関連する問題