2016-05-10 8 views
1

私は、ラムダの2つの基準に依存するjava8でコンパレータを記述しようとしています。私はList人です。 Personは、このメソッドがあります。コンパレータを複数のフィールドで短縮するには?

Person{ 
    String getFirstName(); 
    String getLastName(); 
    int getHeight(); 
    Date getBirthday(); 
} 

リストのソートは、意思によって選択することができる2つのcriteriasに依存しています。だから、リストはファーストネームと誕生日、またはファーストネームと高さなどでソートする必要があります。

私のアプローチは、スイッチのケースブロックを作成して、さまざまな条件の組み合わせを調べることでした。しかし、このアプローチは大きくなりすぎています。

switch (holder.criteria1) { 
     case FIRSTNAME: 
      switch (holder.criteria2) { 
       case FIRSTNAME: 
        list.sort(Comparator.comparing(Person::getFirstName, 
          Comparator.nullsFirst(String::compareTo))); 
        break; 
       case LASTNAME: 
        list.sort(Comparator.comparing(Person::getFirstname, 
          Comparator.nullsFirst(String::compareTo)).thenComparing(
          Person::getLastName, Comparator.nullsFirst(String::compareTo))); 
        break; 
       case HEIGHT: 
        list.sort(Comparator.comparing(Person::getFirstname, 
          Comparator.nullsFirst(String::compareTo)).thenComparing(
          Person::getHeight, Comparator.nullsFirst(Integer::compareTo))); 
        break; 
       case BIRTHDAY: 
        list.sort(Comparator.comparing(Person::getFirstname, 
          Comparator.nullsFirst(String::compareTo)).thenComparing(
          Person::getBirthday, Comparator.nullsFirst(Date::compareTo))); 
        break; 
      } 
      break; 

すべてのケースの組み合わせでこれを繰り返す必要があります。基準2の4つのケースのうち3つはほぼ同じであり、メソッド名とタイプのみが変化します。これは非常に醜い長いコードであり、私はより良い方法でそれを再設計したいと思います。

おそらく反射を使用してこれを短縮する方法はありますか?

+0

を単にコードを短くしようとする反射を導入しないで下さい。 – Kayaman

+2

各基準ごとに1つのコンパレータを作成し、選択したオプションに応じて正しいコンパレータを供給します。 – aioobe

+0

第2のスイッチが '' 'holder.criteria2'''または何かをスイッチしてはいけませんか? –

答えて

3

あなたの列挙値にコンパレータを保存し、その後、必要に応じて組み合わせることができます。

enum SortOn { 
    FIRSTNAME(Comparator.comparing(Person::getFirstName, 
     Comparator.nullsFirst(String::compareTo))), 
    LASTNAME(Comparator.comparing(Person::getLastName, 
     Comparator.nullsFirst(String::compareTo))), 
    HEIGHT(Comparator.comparing(Person::getHeight, 
     Comparator.nullsFirst(Integer::compareTo))), 
    BIRTHDAY(Comparator.comparing(Person::getBirthday, 
     Comparator.nullsFirst(Date::compareTo))); 

    public final Comparator<Person> comparator; 

    private SortOn(Comparator<Person> comparator) { 
     this.comparator = comparator; 
    } 
} 
... 
public void sort(SortOn criteria1, SortOn criteria2) { 
    if(criteria1 == criteria2) { 
     list.sort(criteria1.comparator); 
    } else { 
     list.sort(criteria1.comparator.thenComparing(criteria2.comparator)); 
    } 
} 
+0

ありがとうございます。私はちょうど新しいことを学びました! – htz

3

多分あなたはそのように行うcoud:

public enum Holder{ 
FIRSTNAME{ 
    @override 
    Function getFunction(){ 
    return Person::getFirstName; 
    } 
} 

........ 
abstract Function getFunction(); 
} 

次に、あなただけのこの呼び出しが必要になります。

list.sort(Comparator.comparing(holder1.getFunction(), 
          Comparator.nullsFirst(String::compareTo)).thenComparing(
         holder2.getFunction(), Comparator.nullsFirst(String::compareTo))); 
1

Jorn Vernee’s answerの付録として、ここではコードを避けて派生したバリアント複製:すべてのプロパティはComparableタイプを持っているので、それらの自然順序が望まれる場合

enum SortOn { 
    FIRSTNAME(Person::getFirstName), 
    LASTNAME(Person::getLastName), 
    HEIGHT(Person::getHeight), 
    BIRTHDAY(Person::getBirthday); 

    public final Comparator<Person> comparator; 

    private <U extends Comparable<U>> SortOn(Function<Person,U> f) { 
     this.comparator = Comparator.comparing(f, 
      Comparator.nullsFirst(Comparator.naturalOrder())); 
    } 
    private SortOn(ToIntFunction<Person> f) { 
     this.comparator = Comparator.comparingInt(f); 
    } 
} 

が、それらは、同様に処理することができます。

HEIGHTインスタンスは、ここで代替コンストラクタを使用して、intプロパティに固有のComparatorを作成し、ボクシングオーバーヘッドを回避します。これらの値はnullになることはありませんので、null -checkもこの特定のプロパティでは廃止されています。

この列挙体は、やはり同じ方法で使用できます。

public static void sort(List<Person> list, SortOn criteria1, SortOn criteria2) { 
    if(criteria1 == criteria2) { 
     list.sort(criteria1.comparator); 
    } else { 
     list.sort(criteria1.comparator.thenComparing(criteria2.comparator)); 
    } 
} 

や基準の任意の数のサポート:

public static void sort(List<Person> list, SortOn... criteria) { 
    list.sort(Arrays.stream(criteria).map(c -> c.comparator) 
     .reduce(Comparator::thenComparing) 
     .orElseThrow(() -> new IllegalArgumentException("no criteria given"))); 
} 
関連する問題