質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

解決済

複数のフィールドで比較する null を許容する Comparator を簡潔に生成するためのメソッドのエラーを解決したい

Risu
Risu

総合スコア2

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

3回答

0評価

0クリップ

314閲覧

投稿2022/05/17 09:27

編集2022/05/18 22:33

前提

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 を消してみましたが、同様にコンパイルエラーが発生しました

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

xebme

2022/05/17 11:29

Function<C, ? extends K>... keyExtractors Data String Data Integer CとKの型が異なりますが、全て同じでなければならないのかな? Data Stringに統一したらどうなりますか?
Risu

2022/05/17 11:46

Data String で統一したらエラーを吐かなくなりました。ご指摘ありがとうございます。 ジェネリクスについて勘違いしていたようです… もしできるのなら型が異なるもので動かしたいのでまた考えてみます。
xebme

2022/05/17 12:13

.reduce(Comparator::thenComparing) 型が同じでなればthenComparingで次に引き渡せないと思いますが、他に解決方法がないとは断言できません。
Risu

2022/05/17 12:20

その前の .map(f -> comparing(f, nullsFirst(naturalOrder()))) で型を Function<C, ? extends K> から Comparator<C> に変換しているので問題ないかと思います。 (メソッドを使わずに書く場合だと型が異なっても動いたことからの推測です。) Cはメソッドを呼び出す際に全て同じものになります。(この例ではData2 String が引数に入ることはありません) わかりづらく申し訳ありません。
xebme

2022/05/17 12:50

はいそのとおりです。「引き渡せない」のは間違いです。
Risu

2022/05/17 12:52

わかりました。ありがとうございます。
xebme

2022/05/17 12:56

今の「Comaprator<C>に変換しているので問題ないか」をヒントにすると可変長引数の部分 Function<C, ? extends K>... keyExtractors これを以下のいずれかに変更するという解決策が思い浮かびます Comparator<C>... comparators Supplier<Comparator<C>>... suppliers
Risu

2022/05/18 01:59

遅くなってしまいすみません。 回答欄の方でまとめて返信させていただきます。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。