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

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

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

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

Q&A

解決済

2回答

1539閲覧

ラムダ式について教えてください

ildahhk

総合スコア16

Java

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

0グッド

1クリップ

投稿2018/10/24 18:31

初心者なので試行錯誤しながらやっているのですが、教えていただきたいことがあります。

ラムダ式についてラムダ式が書ける条件として
1:どの関数型インターフェイス型を実装するオブジェクトを返すか分かっている。
2:その関数型インターフェイス型の引数の型が分かっているか、メソッド参照などによって一つに決めることができる。

この1と考えた2両方満たす場合にラムダ式によって関数型インターフェイスを実装するオブジェクトが生み出すことができる。

と考えたのですが、この認識でよろしいでしょうか?一応公式サイトなどは見たりしたのですがあまりしっくりこなかったので

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

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

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

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

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

yohhoy

2018/11/02 11:45

Java以外のプログラミング言語でラムダ式を扱ったことはありますか?Javaのラムダ式は少々クセが強い気がしますから。
ildahhk

2018/11/09 17:30

いえ、javaしかやっておりません。
guest

回答2

0

ベストアンサー

1はまあその通りですが、2は主従が逆になってるような感じがします。
1も見ようによっては主従が逆転してるような気もしますが…

まず理解しておいてほしいのは、ラムダ式の本質は無名クラスであるということです。
無名クラスを作成するときは、通常次のように生成するのですが…

java

1Runnable r = new Runnable(){ 2 @Override 3 public void run() { 4 // 何かの処理 5 } 6};

この例で考えると

  • Runnableに代入しようとしているんだからわざわざnew Runnable()って書かなくてもいいんじゃね?
  • Runnableの無名クラス作ってるんだから必要なのはrun()の中身だよね。じゃあrunって名前もいらなくね?

という感じで、無駄を削っていったのが(Javaにおける)ラムダ式です。

java

1Runnable r = () -> 何かの処理;

当然このためには、「作成しようとしている匿名クラスが何を実装するものなのか」がはっきりわかる必要があります。そういう意味では

1:どの関数型インターフェイス型を実装するオブジェクトを返すか分かっている。

はその通りになります。ただし、「何を返すかわかっている」というよりむしろ「変数の型で要求されているものを作成する」ニュアンスが強いです。ですから、

2:その関数型インターフェイス型の引数の型が分かっているか、メソッド参照などによって一つに決めることができる。

というよりもむしろ、「1により型が確定するので、引数として使うべき型も確定する」という関係でとらえるべきだと思います。

単に「ラムダ式を書ける条件」というなら以下のいずれかになるでしょう。
1.関数型インタフェース型の変数に代入する(例は上記で既出)
2.関数型インタフェース型の引数を要求するメソッドまたはコンストラクタに渡す

java

1// ThreadクラスのコンストラクタはRunnableを引数に要求するものがある 2Thread thread = new Thread(() -> 何かの処理);

3.キャストする

java

1Object o = (Runnable) () -> 何かの処理;

投稿2018/10/24 20:03

編集2018/10/25 12:53
swordone

総合スコア20651

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

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

ildahhk

2018/10/25 07:52

丁寧に回答いだだきありがとうございます。 ラムダ式を使う場面は色々あると思うのですが、例えばあるジェネリクメソッドが引数にFanction<T,R>を持つ場合には最初に、例えばFanction<String,Integer>型にするように決まってなくても、型推論などによりTだけ確定していればRは決まってなくてもよい。メソッド参照についてはT,R両方未定でも書くことができる。という場面もカバーするための回りくどい1,2の記述をしています。 例示されました、変数宣言をしてラムダ式を使って関数型インターフェースを実装したオブジェクトをそれに代入する場面ではおっしゃる通りの話で1,2で分ける意味はないです。 説明不足があったかもしれないですが、1の意味は例えばFanction<T,R>の T,Rは未定でもFanctionであるということが分かっていることという条件です。分かりにくくて申し訳ないです。 これを踏まえて意見頂けると嬉しく思います。
swordone

2018/11/02 13:37

何の意見を求められているのか未だにわからないです。
ildahhk

2018/11/09 17:48

返信遅れて申し訳ないです。気づかなくて、すいません。 何についての意見が知りたいのかということですが自分が知りたいことは、ラムダ式を使える条件はジェネリクスも考慮して考えたときにどうなるかということです。自分が考えた条件を説明すると、例えばFanction<T,R>型のオブジェクトが入る場所にラムダ式を書こうとする場合に、T,Rが具体的な型にどちらも決まってない場合はメソッド参照のみ使えて、普通のラムダ式は使えない。Tがわかっているならメソッド参照だけでなく、普通のラムダ式も使えるようになる。という条件なのですがこれについてまず合っているのか、また、間違いがあればその間違いをお聞きしたくて質問させて頂きました。長文申し訳ないです。よろしければ回答頂けると嬉しく思います。
swordone

2018/11/09 18:47

そもそも「TもRも決まっていない」ということはほぼありえません。 Streamに使う場合はそのStreamで扱う型がTになりますし、Rはそのラムダやメソッド参照の返り値の型として自動的に決まります。変数に収める場合でもFunctionの型引数まで宣言して格納するのが普通です。どっちも決まらないというのは未加工型やFunction<?, ?>の場合くらいですが、その場合でも最悪Objectとしては扱えます。
ildahhk

2018/11/09 19:38

回答ありがとうございます。少しまだお聞きしたい部分がありまして、申し訳ないのですが書かせていただきます。 TもRも決まっていないというときにラムダ式を書くことは、ほぼありえないということですが次のように定義されたメソッドのようにstaticなジェネリックメソッドをつくるとありえるのではないでしょうか? たとえばこのようなメソッドたちがSampleクラスにあったとします。 public static <T,R> void sample(Function<T,R> a) { } public static String sample_2(String s) { return s; } これをmainメソッドにおいて呼び出す場合に Sample.sample(Sample::sample_2); Sample.sample(s -> Sample.sample_2(s)); この二つにおいて上はコンパイルエラーにはならないですが、下はコンパイルエラーとなります。 このような場合も想定した上でのラムダ式の使える条件というものを考えた場合にどういう理解がただしいのか?を知りたいのです。Streamなどの大抵の場合においてTが決まっているというのは自分もそう思うのですが、上で挙げたような状況にも対応できるような統一的な理解として、自分の理解が正しいかどうか意見を頂けると嬉しく思います。長文失礼しました。
momon-ga

2018/11/13 01:37

型推論が利かないからコンパイルエラーになっているのですよね? Sample.sample((String s) -> Sample.sample_2(s)); というふうに、ラムダ式は使えます(書けます)けど。
ildahhk

2018/11/13 13:29

教えていただきありがとうございます。 つまり、ラムダ式においても、明示的にFunction<T,R>のTの型を定めることができるならそこに代入可能ということになりますね。逆に言えばラムダ式のTの型を明示的に書かなければ、ラムダ式の右辺で呼び出すメソッドの引数からおっしゃられた通りTを推量してはくれないということになります。その問題を右辺でメソッドを単独で使うときにのみですが解決するのがメソッド参照ということになっているんだなと考えが深まりました。ラムダ式やメソッド参照ではそのラムダ式を受け取る型の引数のジェネリクスがあらかじめ決まっていなくても、型を明示したラムダ式やメソッド参照によって決めることができれば 、ラムダ式やメソッド参照はそこに入れることができるということになりますね。これらの考えをもとに、自分の考えを修正しますと、 ラムダ式が書ける条件 1:どの関数型インターフェイス型を実装するオブジェクトを返すか分かっている。ただしそのジェネリクスは決まっていなくてもよい。 2:その関数型インターフェイス型の引数の型が決まっているかもしくは何らかの方法で推量されているか、メソッド参照や引数の型を明示的にしたラムダ式などによって一つに決めることができるならば用いることができる。 となります。 大体このような理解でいいんじゃないかという気もしてきました。もし間違いがありましたら教えていただければありがたいです。長々とすいません。読んでいただきありがとうございました。
guest

0

参考情報

  • Java のラムダ式と StreamAPI。入門レベルを図解で

http://ailaby.com/java_lambda/

...
簡潔に書く上でポイントとなるのが関数型インターフェースの特徴です。
関数型インターフェースには抽象メソッドが1つしかありません。
1つだけなら、メソッド名をわざわざ実装側に書かなくてもコンパイラには判るはずです。
そして引数の型や戻り値もコンパイラには判るはずです。
そういったコンパイラには判るはずの情報を省略して 必要な部分だけ 記述するのがラムダ式です。
...

投稿2018/10/24 21:56

katoy

総合スコア22324

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

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

ildahhk

2018/10/25 08:01

回答ありがとうございます。 関数型インターフェースのジェネリクスとラムダ式というテーマで質問させて頂いたのですが、関数型インターフェースが総称型で定義されている場合引用文にありますメソッド参照は引数の型が、ラムダ式、メソッド参照では返り値の型がラムダ式、メソッド参照の使用時に決まってない場合もあるのでそういった場合にも対応可能な使用条件を探しています。 長くなって申し訳ないですが、参考資料は読ませて頂きました。感謝します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問