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

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

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

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

Q&A

解決済

2回答

877閲覧

Comparatorインターフェイスについて

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

3グッド

3クリップ

投稿2017/11/10 01:23

編集2017/11/10 02:22

Comparatorを生成するstaticメソッドやdefaultメソッドの使用方法で、Comparatorのメソッドを続けて呼び出す際に(なんか用語ありましたっけ?)、型を指定しないとコンパイルエラーとなってしまう原因が分かりません。

###List<Element>をCollections.sortを使ってn1>n2>n3の昇順に並び替える

  1. Elementクラス(getterは省略してます)

java

1class Element { 2 int n1; 3 int n2; 4 int n3; 5 public Element(int n1, int n2, int n3) { 6 this.n1 = n1; 7 this.n2 = n2; 8 this.n3 = n3; 9 } 10}

2.これは問題ない

java

1List<Element> list = new ArrayList<>(); 2/* listに値を入れる処理 */ 3Collections.sort(list, Comparator.comparingInt(e -> e.n1));

3.こうするとコンパイルエラー

java

1Collections.sort(list, Comparator.comparingInt(e -> e.n1) 2 .thenComparingInt(e -> e.n2) 3 .thenComparingInt(e -> e.n3));

4.comparingの前に型を指定するか

java

1Collections.sort(list, Comparator.<Element>comparingInt(e -> e.n1) 2 .thenComparingInt(e -> e.n2) 3 .thenComparingInt(e -> e.n3));

5.ラムダ式の引数に型を入れれば通る

java

1Collections.sort(list, Comparator.comparingInt((Element e) -> e.n1) 2 .thenComparingInt(e -> e.n2) 3 .thenComparingInt(e -> e.n3));

3.が通らないのは型を指定しないとComparator<Object>が返るからでしょうか?
ではなぜ、指定していない2.が通り、3.がダメで、4.と5.が通るのか分かりません。
以下に疑問点をまとめます。

2. → 型を指定してないのに通るのはなぜか
3. → 続けてthenComparingを呼べないのはなぜか
5. → ラムダ式に型を入れるだけで4.と同じ効果を得られるのはなぜか

型パラメータについての知識が稚拙ですが、ご教授ください。

追記:
コンパイルエラーは以下が表示されます

n1 は解決できないか、フィールドではありません
n2 は解決できないか、フィールドではありません
n3 は解決できないか、フィールドではありません
root_jp, LouiS0616, yohhoy👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2017/11/10 02:01

「コンパイルエラー」とありますが、どのようなメッセージになるか追記してもらえませんでしょうか。
退会済みユーザー

退会済みユーザー

2017/11/10 02:23

追記しました。
yohhoy

2017/11/10 16:21

FYI: "Comparatorのメソッドを続けて呼び出す"=メソッドチェーンと呼ばれますね。
guest

回答2

0

ベストアンサー

Javaの総称型に関して、型推論という機能があります。
Collections.sortメソッドの引数は(List<T>, Comparator<? super T>)となっています。このlistの部分にList<Element>が渡っているので、Comparatorの型もElementかその親クラスのものである必要があると推測してくれるのです。

Comparator.comparingIntはComparator<T>を返すstaticメソッドです。このメソッドを渡すと、このTの部分をElementであるとしてコンパイルしてくれるのです。このため、2はコンパイルが通ります。

java

1// Comparator.comparingIntの総称型を自動でElementと推定 2Collections.sort(list, Comparator.comparingInt(e -> e.n1));

一方、つないで書いているthenComparingIntメソッドはComparatorのdefaultメソッドで、Comparator<T>のオブジェクトに使うことでComparator<T>を返すインスタンスメソッドのような役割です。
3のComparatorの書き方の場合、最初のcomparingIntメソッドの時点で型を推測する根拠が何もないため、TをObjectとして扱います。これにthenComparingIntメソッドを使うため、TがObjectのままとなります。
つまり、comparingIntやthenComparingIntに渡しているラムダ式のeがObjectとして扱われ、Objectクラスにn1,n2,n3というフィールドがないため、ご質問のエラーが出ます。

java

1// この段階では型推論が効かないため、comparingIntの総称型はObject扱い 2// つまり、ラムダ式はToIntFunction<Object>で、eの型がObject扱い 3Collections.sort(list, Comparator.comparingInt(e -> e.n1) 4// これ以降はComparator<Object>に対してthencomparingIntを呼んでいるため、 5// 引数ラムダ式はToIntFunction<Object> 6 .thenComparingInt(e -> e.n2) 7 .thenComparingInt(e -> e.n3));

この問題は、comparingIntにおけるTがElementとわかれば解決します。そのため、総称型を明示的に指定する(4の方法)か、ラムダ式の引数、つまりFunctionの型を明示する(5の方法)ことでコンパイルが通るようになるのです。

java

1// comparingIntの総称型を明示的にElementにすることで、引数ラムダ式をToIntFunction<Element>と推定 2Collections.sort(list, Comparator.<Element>comparingInt(e -> e.n1) 3// 以降もComparator<Element>に対するメソッドのため、Elementに対する操作とわかる 4 .thenComparingInt(e -> e.n2) 5 .thenComparingInt(e -> e.n3));

java

1// ラムダ式の引数型をElementと明示することて、このラムダ式がToIntFunction<Element>に確定。 2// これにより、comparingIntの総称型もElementに確定できる。 3Collections.sort(list, Comparator.comparingInt((Element e) -> e.n1) 4// 以下、先述通り 5 .thenComparingInt(e -> e.n2) 6 .thenComparingInt(e -> e.n3));

投稿2017/11/10 02:43

編集2017/11/10 19:47
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

2.について
コンパイル時に、Elementとして確定できると型推論してコンパイラが判断してよしなにやってくれるから。

Collections.sort(list, Comparator.comparingInt(e -> e.n1));

においては、コンパイラが第一引数のlistで利用しているElement型の型パラメタで型解決してくれるから。

3.について
下記の場合の戻り値は

Comparator.comparingInt(e -> e.n1)

時点の戻り値はDefaultメソッドで <T,U extends Comparable<? super U>> Comparator<T>
として型パラメタの型が確定できません。ですが、2の場合はコンパイラがうまく
やってくれます。ただ、明確には確定できない状態の時には戻り値の型は上記の通り
確定できません。戻り値はT(Object)であり、T型変数はeその時点では確定できないため
T型eにはn2なんてないよ?って怒られます。

ただ、型パラメタの型を確定させてあげれば戻り値の方も引数の型に紐づけられて返すので
4、5はコンパイルが通るということになります。

// この時点で Comparatorクラスのメソッド comparingInt の引数が Element型 // と確定し、同時に戻り値も Comparator<Element> で確定します。 Comparator.comparingInt((Element e) -> e.n1)) // その戻り値は Element を利用することが確定しているComparatorクラスなので // 以下呼び出しの引数に定義する関数(ラムダ式)内 e は Element と確定します。 .thenComparingInt(e -> e.n2) // 以下については、当該メソッド内での型パラメタ<T>は Elementとして解釈する // というのをジェネリクスで定義しているので、実質上記と等価となり、引数eは // Element型、戻り値も Comparator<Element> で確定します。 Comparator.<Element>comparingInt(e -> e.n1)) .thenComparingInt(e -> e.n2) // 上記の呼び出しで、戻り値は Comparator<Element> と確定しているので // 以下呼び出しの引数に定義する関数(ラムダ式)内 e は Element と確定します。 .thenComparingInt(e -> e.n3);

上記より、コンパイラが解決できるかどうかだと思います。

投稿2017/11/10 02:52

kanimaru

総合スコア1013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問