4

いくつかComparatorの s があります。1 つはDates、1 つは小数、もう 1 つはパーセンテージなどです。

最初は、10 進コンパレータは次のようになりました。

class NumericComparator implements Comparator<String> {

  @Override
  public int compare(String s1, String s2) {
    final Double i1 = Double.parseDouble(s1);
    final Double i2 = Double.parseDouble(s2);
    return i1.compareTo(i2);
  }

}

人生はシンプルでした。もちろん、これは文字列が解析できない場合を処理しません。だから私は改善しましたcompare()

class NumericComparator implements Comparator<String> {

  @Override
  public int compare(String s1, String s2) {
    final Double i1;
    final Double i2;

    try {
      i1 = Double.parseDouble(s1);
    } catch (NumberFormatException e) {
      try {
        i2 = Double.parseDouble(s2);
      } catch (NumberFormatException e2) {
        return 0;
      }
      return -1;
    }
    try {
      i2 = Double.parseDouble(s2);
    } catch (NumberFormatException e) {
      return 1;
    }

    return i1.compareTo(i2);
  }
}

人生はより良くなりました。テストはより堅実に感じました。nullしかし、私のコード レビュー担当者は、「 s はどうですか?」と指摘しました。

すばらしいので、上記を繰り返すNullPointerExceptionか、メソッド本体の先頭に次を追加する必要があります。

if (s1 == null) {
  if (s2 == null) {
    return 0;
  } else {
    return -1;
  }
} else if (s2 == null) {
  return 1;
}

この方法は巨大です。最悪の部分は、異なるタイプの文字列を比較する他の 3 つのクラスでこのパターンを繰り返す必要があり、解析中に他の 3 つの例外が発生する可能性があることです。

私は Java の専門家ではありません。あえぎ-コピーして貼り付けるよりもクリーンできちんとした解決策はありますか? 文書化されている限り、複雑さの欠如と正確さを交換する必要がありますか?


更新:Comparator値を処理するのは の仕事ではないことを示唆する人もいnullます。並べ替えの結果がユーザーに表示されるので、null を一貫して並べ替える必要があります。

4

12 に答える 12

2

この質問には多くの主観的な答えがあります。これが私自身の $.02 です。

まず、あなたが説明している問題は、これらのパターンを簡潔に説明できる、一流の関数を欠いている言語の標準的な症状です。

第 2 に、私の意見では、2 つの文字列の 1 つが double の表現と見なされない場合、2 つの文字列を Double として比較するのはエラーになるはずです。(null などについても同様です。) したがって、例外の伝播を許可する必要があります。これは論争の的となる意見になると思います。

于 2009-11-05T19:00:57.483 に答える
1

コンパレータを改善する方法は次のとおりです。

まず、値を変換する方法を抽出します。それは繰り返されています、複数の試み...キャッチは常に醜いです->それらの数をできるだけ少なくする方が良いです。

private Double getDouble(String number) {
 try {
  return Double.parseDouble(number);
 } catch(NumberFormatException e) {
  return null;
 }
}

次に、コンパレータのフローをどのようにするかを示す簡単なルールを書き留めます。

if i1==null && i2!=null return -1
if i1==null && i2==null return 0
if i1!=null && i2==null return 1
if i1!=null && i2!=null return comparison

最後に、実際のコンパレータに恐ろしい難読化を行って、コードレビューでいくつかのWTFを上げます(または他の人が言うように、「コンパレータを実装する」):

class NumericComparator implements Comparator<String> {

     public int compare(String s1, String s2) {
      final Double i1 = getDouble(s1);
      final Double i2 = getDouble(s2);

      return (i1 == null) ? (i2 == null) ? 0 : -1 : (i2 == null) ? 1 : i1.compareTo(i2);
     }
     private Double getDouble(String number) {
          try {
               return Double.parseDouble(number);
          } catch(NumberFormatException e) {
               return null;
          }
     }
}

...はい、それは分岐するネストされた三項です。誰かがそれについて不平を言うなら、ここで他の人が言っていることを言ってください:ヌルを扱うことはコンパレータの仕事ではありません。

于 2009-11-05T20:38:31.623 に答える
1

解析を処理し、null または解析例外の場合に特定の値を返すユーティリティ メソッドを作成できます。

于 2009-11-05T18:58:04.160 に答える
1

ここには 2 つの懸念事項が混在しているようで、別々のコンポーネントに分割する必要があるかもしれません。次の点を考慮してください。

public class ParsingComparator implements Comparator<String> {
  private Parser parser;

  public int compare(String s1, String s2) {
    Object c1 = parser.parse(s1);
    Object c2 = parser.parse(s2);
    new CompareToBuilder().append(c1, c2).toComparison();
  }
}

Parser インターフェースには、数値、日付などの実装があります。Parser インターフェースに java.text.Format クラスを使用できる可能性があります。commons-lang を使用したくない場合は、CompareToBuilder の使用を null を処理するロジックに置き換え、c1 と c2 のオブジェクトの代わりに Comparable を使用できます。

于 2009-11-05T22:36:20.703 に答える
1

tl;dr: JDK からガイダンスを受けてください。Double コンパレータは、非数値または null に対して定義されていません。有用なデータ (Doubles、Dates、Dinosaurs など) を人々に提供してもらい、そのためのコンパレータを記述します。

私が知る限り、これはユーザー入力の検証のケースです。たとえば、ダイアログ ボックスから入力を取得している場合、Double、Date、または入力ハンドラーにあるものである解析可能な文字列があることを確認する正しい場所。ユーザーがタブを離して「OK」または同等のボタンを押す前に、問題がないことを確認してください。

これが私がこれを考える理由です:

最初の質問: 文字列が数値として解析できない場合、間違った場所で問題を解決しようとしていると思います。たとえば、 と比較しようとすると"1.0""Two"ます。2 番目は明らかに Double として解析できませんが、1 番目よりも小さいですか? それとも大きいですか。どちらが大きいかをユーザーが尋ねる前に、ユーザーは Strings を Doubles に変換する必要があると私は主張します (たとえば、Double.compareTo で簡単に答えることができます)。

2 番目の質問: 文字列が"1.0"との場合null、どちらが大きいですか? JDK ソースは Comparator で NullPointerExceptions を処理しません。null を指定すると、オートボクシングは失敗します。

最悪の部分は、異なるタイプの文字列を比較する他の 3 つのクラスでこのパターンを繰り返す必要があり、解析中に他の 3 つの例外が発生する可能性があることです。

コードに到達する前に例外処理を処理して、解析を Comparator の外部で行う必要があると私が主張する正確な理由です。

于 2009-11-05T20:08:00.953 に答える
0

あなたのニーズと Ewan の投稿によると、再利用できる構造を抽出する方法があると思います。

class NumericComparator implements Comparator<String> {
    private SafeAdaptor<Double> doubleAdaptor = new SafeAdaptor<Double>(){
        public Double parse(String s) {
            return Double.parseDouble(s);
        }
    };
    public int compare(String s1, String s2) {
        final Double i1 =doubleAdaptor.getValue(s1, "s1");
        final Double i2 = doubleAdaptor.getValue(s2, "s2");
        return i1.compareTo(i2);
    }
}

abstract class SafeAdaptor<T>{
    public abstract T parse(String s);
    public T getValue(String str, String name) {
        T i;
        if (str == null) {
            throw new NullPointerException(name + " is null"); // String
        }
        try {
            i = parse(str);
        } catch (NumberFormatException e) {
            throw new ClassCastException(name + " incorrect format"); // Comparator
        }
        return i;
    }

}

他の場合に再利用できる抽象クラスとしてメソッドを抽出します(クラス名はひどいですが)。

乾杯。

于 2009-11-06T02:21:13.803 に答える