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

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

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

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

Q&A

解決済

2回答

7547閲覧

Stream処理における、型推論されない原因がわからない

waka_

総合スコア10

Java

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

1グッド

1クリップ

投稿2020/03/07 18:08

編集2020/03/08 03:50

概要

Streamを用いたComparator生成時、↓この実装で型推論されない理由を教えていただきたいです。

java

1Comparator<Data> comparator = Comparator 2 .comparing(d -> d.getkey1()) 3 .thenComparing(d -> d.getkey2());

(全実装は最後に記載いたします)

詳細

List<Data> を2つのkeyでソートする処理を実装しています(key1でソート→key1が同値の場合にはkey2でソート)。

Comparator作成時、ソース中① NGの実装では以下内容のコンパイルエラーが発生します。

<T, U> comparing(Function<? super T,? extends U>) の型引数を推論できません

しかし、Comparator作成Stream処理を2回に分けた、②の処理は問題なく動作します。

・なぜ①のように、2段階の処理を一度に行いComparatorを作成する実装では型推論されないのか
・なぜ、②のように2行に分けた実装ならば型推論されるのか

をご教授下さい。

java

1import java.util.ArrayList; 2import java.util.Comparator; 3import java.util.List; 4import java.util.Random; 5import java.util.stream.Collectors; 6 7public class SortTest { 8 9 public static void main(String[] args) { 10 sortTest(); 11 } 12 13 public static void sortTest() { 14 List<Data> dataList = create(); 15 16 // ① NG : なぜか型推論できない 17 Comparator<Data> comparator = Comparator 18 .comparing(d -> d.getKey1()) 19 .thenComparing(d -> d.getKey2()); 20 21 // ② OK (別々にComparator生成) 22 // Comparator<Data> comp1 = Comparator.comparing(d -> d.getKey1()); 23 // Comparator<Data> comp2 = Comparator.comparing(d -> d.getKey2()); 24 // Comparator<Data> comparator = comp1.thenComparing(comp2); 25 26 // ③ OK (型を指定すればOK) 27 // Comparator<Data> comparator = Comparator 28 // .comparing((Data d) -> d.getKey1()) 29 // .thenComparing(d -> d.getKey2()); 30 31 // ③ OK (メソッド参照でもOK) 32 // Comparator<Data> comparator = Comparator 33 // .comparing(Data::getKey1) 34 // .thenComparing(Data::getKey2); 35 36 List<Data> sortedList = dataList.stream().sorted(comparator) 37 .collect(Collectors.toList()); 38 39 showObjList(sortedList); 40 } 41 42 static class Data { 43 private final long key1; 44 private final long key2; 45 private final String str; 46 47 Data(long key1, long key2, String str) { 48 this.key1 = key1; 49 this.key2 = key2; 50 this.str = str; 51 } 52 53 public long getKey1() { 54 return this.key1; 55 } 56 57 public long getKey2() { 58 return this.key2; 59 } 60 61 public String toString() { 62 return String.valueOf(key1) 63 + " " 64 + String.valueOf(key2) 65 + " " 66 + str; 67 } 68 } 69 70 private static void showObjList(List<Data> DataList) { 71 for (Data Data : DataList) { 72 System.out.println(Data.toString()); 73 } 74 } 75 76 private static List<Data> create() { 77 List<Data> retList = new ArrayList<>(); 78 Random rnd = new Random(); 79 for (int i = 0; i < 100; i++) { 80 int key1 = rnd.nextInt(10); 81 int dc = rnd.nextInt(3); 82 String str = String.valueOf(new Random().nextInt()); 83 retList.add(new Data(key1, dc, str)); 84 } 85 return retList; 86 } 87} 88
LouiS0616👍を押しています

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

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

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

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

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

LouiS0616

2020/03/07 23:33

thenComparing(d -> d.getkey2) ではなく thenComparing(d -> d.getkey2()) ですよね。 ここを修正しても当該エラーは解消しないようですが、話がこんがらがりそうなので修正しておいて下さい。
waka_

2020/03/08 03:51

ご指摘ありがとうございます!該当箇所修正いたしました
guest

回答2

0

この質問を見たときすでに解決済みになっていました。備忘録としてリンクを貼らせてください。
Very confused by Java 8 Comparator type inference
エラーの理由説明はswordoneさんと同じ。

リンク先の情報のとおり、eclipseコンパイラとjdkコンパイラでは結果が異なりました。
eclipseコンパイラの型推論だと疑問が残りますが、jdkコンパイラの結果なら理解できます。

Comparator.<Data, Long>comparing(...).thenComparing(...)という解決法も。

投稿2020/03/08 09:05

xebme

総合スコア1081

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

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

waka_

2020/03/09 02:49

返信遅くなりすいません、 有用な情報共有ありがとうございます!
guest

0

ベストアンサー

問題が起こっているComparator.comparingはstaticメソッドで、
本来明確な型宣言をしない限り、型の根拠となるべき情報がありません。
それが②のような形で左辺の型宣言とつながることにより、型が確定できるのです。
一方、thenComparingComparator<T>のインスタンスメソッドです。
引数に入れるべき型は、インスタンスの型に依存します。
ところが、その元のインスタンスの型が先述のstaticメソッドによるもので、こちらの型が決まりません。
最終形がDataなのはわかっても、その前は「Dataの子クラス」ということしかわからず、どのクラスを参照すべきかが確定できません。そのため、このコンパイルエラーが発生します。

投稿2020/03/08 04:37

swordone

総合スコア20649

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

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

waka_

2020/03/08 06:27

なるほど、理解しました!丁寧に解説いただきありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問