前提
Java 17 で null を許容する Comparator を適用した TreeSet を作成するプログラムを簡略化しようとしています。
Stack Overflow のこの質問の回答にあるコードを弄ってみたのですが、エラーが発生して解決ができません。
https://stackoverflow.com/questions/54095271/how-to-simplify-creation-of-null-safe-comparator-on-multiple-fields
どなたか解決策を教えていただけますと幸いです。(解決できない問題であればその旨教えていただけるだけでも助かります)
実現したいこと・発生している問題
複数のフィールドの値を順にそれぞれ自然順序付けで比較する Comparator で、全てのフィールドに対して nullsFirst を適用するメソッドを書きたいです。
メソッドを使わずに書くとstatic import や定数に定義することはできますが、次のコードを繰り返し書く必要があり冗長なので…
.thenComparing(Data::getter, Comparator.nullsFirst(Comparator.naturalOrder())
Stack Overflow で説明されていたものを使いたいのですが、上のコードでの Data の型も変化するのでそちらもジェネリクスにしたところ、エラーが発生するようになってしまい原因も掴めません。
ジェネリクスについて勘違いしていただけでした。ご指摘ありがとうございました。
ジェネリクス(ソースコード中のK)が可変長引数の中で同じ型でないといけないようです。
ただ、上の目的のためにはそれぞれ別の型を指定したい(その型のcompareToを使用したいため)ので、何か複数の型を指定する方法があれば教えていただきたいです。
(2022/5/17 21:00 追記)
エラーメッセージ (複数の型を指定していた場合のみ発生します)
./Main.java:8: error: method comparatorNullsFirst in class Main cannot be applied to given types; Comparator<Data> comparator = comparatorNullsFirst(Data::getString, Data::getInteger); ^ required: Function<C,? extends K>[] found: Data::getString,Data::getInteger reason: inference variable K has incompatible bounds equality constraints: String,Integer lower bounds: Integer,String where C,K are type-variables: C extends Object declared in method <C,K>comparatorNullsFirst(Function<C,? extends K>...) K extends Comparable<K> declared in method <C,K>comparatorNullsFirst(Function<C,? extends K>...)
該当のソースコード
java
// import文省略 class Main{ public static void main(String[] args) { Comparator<Data> comparator = comparatorNullsFirst(Data::getString, Data::getInteger); /*この部分でそれぞれのFunctionが同じ型を返さないと 上記のエラーメッセージでコンパイルエラーになるのですが、 複数の型を指定したいです。*/ TreeSet<Data> set = new TreeSet<Data>(comparator); } @SafeVarargs @SuppressWarnings("varargs") private static <C, K extends Comparable<K>> Comparator<C> comparatorNullsFirst( Function<C, ? extends K>... keyExtractors) { return Arrays.stream(keyExtractors) .map(f -> Comparator.comparing(f, Comparator.nullsFirst(Comparator.naturalOrder()))) .reduce(Comparator::thenComparing) .orElseThrow(() -> new IllegalArgumentException("The keyExtractors must not be empty.")); } }
java
class Data { private String string; private Integer integer; String getString() { return string; } Integer getInteger() { /*このメソッドがStringを返すようにすれば問題ないのですが、 IntegerとしてでなくStringとして比較されてしまうのでできません*/ return integer; } }
試したこと
-
引数をリストにしてみましたが、呼び出し側で別のコンパイルエラーが発生するようになりました。 -
ジェネリクスの extends を消してみましたが、同様にコンパイルエラーが発生しました
まだ回答がついていません
会員登録して回答してみよう