Slide 1

Slide 1 text

前回つまづいたところのまとめ

Slide 2

Slide 2 text

今回の経緯 1. Java 21におけるデザインパターンを前回のゆるゆるJavaで読みました 2. 一部分のコードの意味がわからず、首を傾げました。 3. 一部分のコードの意味がわかるように、復習のための資料を作成しました。 やっていないこと 1. Strategy パターンを実際に使うタイミングの解説 2. Java21での新しいStrategyパターンの書き方についての解説

Slide 3

Slide 3 text

該当コード public class RevisitedStrategy { public static void main(String[] args) { var endpoint = getEndpoint(); var passInformation = new PassInformation(new UserProfile(true, true, true)); String jwt = endpoint.get(passInformation); System.out.println(jwt); } public static GoogleWalletEndpoint getEndpoint() { var endpoint = new GoogleWalletEndpoint(); endpoint.setStrategy(pass -> "abc"); endpoint.setStrategy(new AddToGoogleWalletLink()::complete); endpoint.setStrategy(new AddToGoogleWalletLink()::preCreated); return endpoint; } } class GoogleWalletEndpoint { private Function strategy; public String get(PassInformation passInformation) {return strategy.apply(passInformation);} public void setStrategy(Function strategy) {this.strategy = strategy;} } 引用元 : revisiting-design-patterns

Slide 4

Slide 4 text

該当コードの解説 endpoint.setStrategy(pass -> "abc"); public void setStrategy(Function strategy) { this.strategy = strategy; } 疑問だった点 : pass -> "abc" このpassがPassInformationの型を満たしていない…? Functionはどこに行ったのか…?

Slide 5

Slide 5 text

誤解1 そもそも型は要らない 公式のJava Laungage Specificationから引用 Lambda Expressions (int x) -> x+1 // Single declared-type parameter (int x) -> { return x+1; } // Single declared-type parameter (x) -> x+1 // Single inferred-type parameter x -> x+1 // Parentheses optional for // single inferred-type parameter

Slide 6

Slide 6 text

誤解2 意味がある文章だと思い込んでいた public void setStrategy(Function strategy) { this.strategy = strategy; } endpoint.setStrategy(pass -> "abc"); どんなPassInformationに対しても、String"abc"を返すという意味 これ以上の意味があるのではないかと勝手に思い込んでいた

Slide 7

Slide 7 text

復習ラムダ式

Slide 8

Slide 8 text

ラムダ式の例1 () -> {} // No parameters; result is void () -> 42 // No parameters, expression body () -> null // No parameters, expression body () -> { return 42; } // No parameters, block body with return () -> { System.gc(); } // No parameters, void block body

Slide 9

Slide 9 text

ラムダ式の例2 () -> { // Complex block body with returns if (true) return 12; else { int result = 15; for (int i = 1; i < 10; i++) result *= i; return result; } }

Slide 10

Slide 10 text

ラムダ式の例3 (int x) -> x+1 // Single declared-type parameter (int x) -> { return x+1; } // Single declared-type parameter (x) -> x+1 // Single inferred-type parameter x -> x+1 // Parentheses optional for (String s) -> s.length() // Single declared-type parameter (Thread t) -> { t.start(); } // Single declared-type parameter s -> s.length() // Single inferred-type parameter t -> { t.start(); } // Single inferred-type parameter (int x, int y) -> x+y // Multiple declared-type parameters (x, y) -> x+y // Multiple inferred-type parameters (x, int y) -> x+y // Illegal: can't mix inferred and declared types (x, final y) -> x+y // Illegal: no modifiers with inferred types

Slide 11

Slide 11 text

Q. ラムダ式ってそもそも何? A. 関数型インターフェースの実装 参考 : https://xtech.nikkei.com/it/article/COLUMN/20140311/542582/?P=6 補足 関数型インターフェース = Java特有の用語

Slide 12

Slide 12 text

関数型 内部状態に関わらず、入力に対して一定の値を返すもの Javaにおいてインターフェースは状態を持たない(抽象クラスは状態をもつ) ここでの状態はフィールド変数のことを指しています。 参考 : Python公式ドキュメント関数型 参考 : "Interfaces have no instance variables" Java Laungage Specification ちなみに、static finalな変数はinterfaceで宣言できます。 ただ、これは定数と呼んで差し支えないでしょう。

Slide 13

Slide 13 text

ラムダ式からラムダ式の外部のインスタンス変数へのアクセスについて 実質的に定数(finalでなくても、変数の再代入が行われないもの)のみアクセス可能 →これは、「関数型」の"定義の状態によらない入力に対する出力"を実現するための制 限と思われます。 ただ、もともと匿名クラスにはそういう制限があった模様です。 日経クロステック いまから覚えるのであれば、関数型という言葉の意味から理解しても良いかと思いま す。

Slide 14

Slide 14 text

そもそもラムダ式とは ラムダ式とは 「ラムダ式は関数型インタフェースを実装した匿名クラス」 引用 : 日経クロステック 個人的にもっと抽象化して言うのであれば 「クラスの定義無しにメソッドを定義する表現方法」

Slide 15

Slide 15 text

広い意味でのラムダ式 参考 : Wikipedia ラムダ式は他の言語でも使用される。 他の言語ではクロージャと呼ばれる機能も、Javaではラムダ式として内包される。 参考 : JSR "Lambda expressions (informally, "closures" or "anonymous methods")" 意訳 : ラムダ式(非公式にはクロージャ・匿名メソッド) 補足 : anonymous = 匿名(自分の名前を隠して知らせないこと) 無名クラスの方が適切と言う表現もある。

Slide 16

Slide 16 text

今回調べてみての感想 1. 張り切ってJava言語仕様書を読んでみたが、大したことは書いていなかった。 2. JVMの仕様書も目次を洗ってみたが、ラムダ式についての記載はなかった。 3. StreamAPIとラムダ式の関係性がいまいち掴めなかった。 StreamAPIのためにラムダ式が導入された? 4. 宣言型の記法とメソッドチェーン的な記法の境界が掴めなかった。 5. 我々はJVMの奴隷かもしれない… Javaとしての仕様なのか、コンピュータの仕様なのか、境界線が理解し難い

Slide 17

Slide 17 text

調べきれなかったこと1 1. Javaの世界では並列処理と並行処理は区別されないということについて理解ができなか った。 2. ラムダ式によってForループより性能が上がるということについて理解ができなかった。 3. ParallelStereamによって並列処理がサポートされていたが、Virtual Threadの登場によっ てラムダ式はどう変化するのか 要は、ラムダ式の内部でバーチャルスレッドをサポートしないのであれば、ラムダ式で の並列処理ではなくThreadを明示的に呼び出したほうが性能が良くなるのでは。 →後に回答が載っている

Slide 18

Slide 18 text

続き 4. なんで型推論できているの? JavaSE 10でvar(型推論)の宣言が可能になっているのにも関わらず、どうして JavaSE8の時からラムダ式は型の省略が許されていたんだろう。 5. 関数型と宣言型の違い JVMがいい感じに処理してくれるように記載するのが宣言型という意味なんだと思いま すが、上手くこの部分を説明できませんでした。

Slide 19

Slide 19 text

@zinbe(杉山さん)さんからの補足 1. 関数型インターフェースだから定数以外の参照が禁止されている訳ではない。 元々の匿名クラスのクラスファイルの後方互換性を保つための仕様 2. Virtual Threadについて StreamのParallel処理とVitual Thread、順次処理の使い分けが現状最適 virtual threadを生で作ったほうが早くなる可能性がある。 virtual threadは今後標準のライブラリに反映されていく 処理効率が上昇できる場合のみ バーチャルスレッドが解消するのはサーバー側のI/Oの処理のボトルネック 大量のデータはコレクションを使う方が効率が良い。 3. 宣言型について パラレルストリームは、並列処理と並行処理をJVMが判断するという点で、宣言型に近 い 4. streamAPIの表現としてラムダ式が導入されている