ここはひどいナットです。私は、varargsとジェネリックスを一緒に使用することの間に衝突があります。与えられたコードを次に示します。Javaでの連鎖比較のための可変引数とジェネリックの結合
public class MyObject implements Comparable<MyObject>
{
private String name;
private int index;
@Override
public int compareTo(MyObject o)
{
if (name.compareTo(o.name) != 0)
return name.compareTo(o.name);
return ((Integer) index).compareTo(o.index);
}
}
私はcompareTo
方法は、複数の条件を比較使用したいです。文字列が同じ場合は、代わりにintを使用します。私が言う通常の状況。
これを一般的に処理する静的メソッドを作成したいと思います。そして、私はこのように呼ばれる新しい方法chainedCompare
たい:
public int compareTo(MyObject o)
{
return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}
をラムダは、Java 8のインターフェイス機能の可変引数です。だから、最初に私はそのような方法を書いた:
public static <T, C extends Comparable<C>> int chainedCompare(T object1, T object2, Function<T, C>... comparisons)
{
int compareValue = 0;
for (Function<T, C> comparison : comparisons)
{
compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
if (compareValue != 0)
break;
}
return compareValue;
}
をしかし、私はこのケースではジェネリック型Cは可変引数配列内のすべてのFunction<T, C>
比較のため、同じタイプでなければならないことを考慮していませんでした。上記のように、私は異なるComparables(例ではStringとIntegerのような)を使いたいと思っています。
それから私はこのバージョンにそれを修正:
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable<?>>... comparisons)
{
int compareValue = 0;
for (Function<T, ? extends Comparable<?>> comparison : comparisons)
{
compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
if (compareValue != 0)
break;
}
return compareValue;
}
タイプCは、ここでは、ワイルドカードに置き換えられます。メソッド呼び出しは現在動作しますが、ワイルドカード型のパラメータcompareTo
のため、メソッド自体はコンパイルされません。
したがって、私は、汎用インターフェイス(汎用インターフェイス)の固定汎用型が必要ですが、一方で、通常はワイルドカードを設定できる別の(第2)汎用タイプの関数インターフェイスが必要です。これを解決するには?
私の唯一の要件は、定義されていない数の比較条件で示されているように静的メソッドを単純なものとして呼び出すことができることです。私は希望のように使用することができ、次のようにメソッドを変更することができましたTunakiの提案に基づいて
:代わりにComparable
を使用しての
@SuppressWarnings("raw-types")
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable>... comparisons)
{
return Arrays.stream(comparisons)
.map(Comparator::comparing)
.reduce(Comparator::thenComparing)
.map(c -> c.compare(object1, object2))
.orElse(0);
}
public int compareTo(MyObject o)
{
return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}
を持つことができます。 Comparator.comparing()をそれぞれの条件ごとに別々に書く必要がなければ、もっと良いでしょう。関数comparison()も関数をとるので、関数varargsを保持し、コンパレータをchainedCompareメソッド内に構築することは涼しいでしょう。しかし、私は以前と同じような一般的な問題を抱えていたと思いますよね?それは解決できませんか? – Arceus
@Arceusはい、あなたは同じ問題に陥ります。私は別の簡単な解決法で編集したことに注意してください。 – Tunaki
あなたの提案は可能な解決策です。この時点でありがとう。しかし、私の本当の問題は、compareToの内容をonelinerにするだけでなく、可能な限り短くすることでした。そして正直なところ、あなたのコードは少し冗長であることがわかります。オーバーライドされたすべてのcompareTo(これは非常に多くになる)のように書く必要があるからです。 – Arceus