Java8 Lambdas 勉強会
Chapter 1, 2
内藤 遥
Table of Contents
1. Introduction
• Why Did They Need To Change Java Again ?
• What Is Functional Programming ?
• Example Domain
2. Lambda Expressions
• Your First Lambda Expression
• How to Spot a Lambda in a Haystack
• Using Values
• Functional Interfaces
• Type Inference
• Key Points
• マルチコア化で処理性能向上を目指す時代
• java.util.concurrent パッケージなどを使った並行処理には限界がある
⇒ ラムダ式を使った関数型プログラミングで簡潔、かつ強力な並行処理の実装
が書ける
• 関数型言語の利点
• 可読性
• 保守性
• バグが少ない
Why Did They Need To Change Java Again ?
• 文字通り「関数」を使用したプログラミング
• 入力した値に対して必ず同じ結果を返す
• オブジェクト指向におけるメソッド(一連の手続きをまとめて名前を付けたもの)
とは異なる
• 関数の特徴
• 参照透過性
• ある関数に同じ入力値を与えれば、いつ評価しても必ず同じ値が得られる
• 変数は一度定義したら二度と変えない(再代入操作で状態を書き換えない)
• 第一級関数
• 変数に代入したり、別の関数の引数や戻り値になったりすることができる
What Is Functional Programming ?
Example Domain
• 本全体を通して、例の提示には共通の問題領域として音楽が使
われる
• 要約は以下の通り
• アーティスト
– 曲を作る個人やグループ
• トラック
• 一つの曲
• アルバム
• 複数のトラックの集合
• 音楽は関数型プログラミングの手法を説明する際に使われる
Your First Lambda Expression
• Swing(JavaのGUIライブラリ)でボタンをクリックした際の、匿名クラ
スを用いたevent listenerの実装
• 不要な行が多い
• 読みにくい
button.addActionListener(new ActionListerner() {
public void actionPerformed(ActionEvent event) {
System.out.println("button clicked");
}
});
Your First Lambda Expression
• ラムダ式を使用
• (メソッドの引数) -> (処理) の形で書ける
• メソッド名や引数の型が省略できる
button.addActionListener(event -> System.out.println("button clicked"));
Your First Lambda Expression
• ラムダ式を使った様々な実装例
Runnable noArguments = () -> System.out.println("Hello world");
ActionListener oneArgument = event -> System.out.println("button clicked");
Runnable multiStatement = () -> {
System.out.println("Hello");
System.out.pringln(" World");
};
BinaryOperator<Long> add = (x,y) -> x + y;
BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
Your First Lambda Expression
• ラムダ式を使った様々な実装例
引数がないときは()のように書ける。
戻り値の型はvoid
Runnable noArguments = () -> System.out.println("Hello world");
Your First Lambda Expression
• ラムダ式を使った様々な実装例
引数が一つのときは左辺の()を省略
できる。引数名は任意で指定可能
ActionListener oneArgument = event -> System.out.println("button clicked");
Your First Lambda Expression
• ラムダ式を使った様々な実装例
処理が複数行に渡る場合は{}をつける
Runnable multiStatement = () -> {
System.out.println("Hello");
System.out.pringln(" World");
};
Your First Lambda Expression
• ラムダ式を使った様々な実装例
処理が一行の場合、returnを
省略できる(x + y の結果を返す処理の実装)
BinaryOperator<Long> add = (x,y) -> x + y;
Your First Lambda Expression
• ラムダ式を使った様々な実装例
引数の型は省略せずにも書ける
BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
Using Values
• 匿名クラスでは、finalのローカル変数、引数が扱える
• ラムダ式では、実質 finalのローカル変数、引数が扱える
• (場合によってはfinalが可読性を損なうこともあるため)
final String name = getUserName();
button.addActionListener(new ActionListerner(){
public void actionPerformed(ActionEvent event){
System.out.println("hi " + name);
}
});
String name = getUserName();
button.addActionListener(event -> System.out.println("hi " + name));
Using Values
• 下記の場合、 nameが実質finalでないのでコンパイルエラーとなる
String name = getUserName();
name = formatUserName(name);
button.addActionListener(event -> System.out.println("hi " + name));
Functional Interfaces
• 関数型インターフェイスとは
• 定義されている抽象メソッドが1つだけあるインターフェイス
• ラムダ式は、関数型インターフェイスに対して適用することができる
• 今後は、関数型インターフェイスをダイアグラムで表現する
• 関数に入っていく矢印は引数を、関数から出ていく矢印は戻り値の型を表す
• 関数型インターフェイスとダイアグラムの例は下記の通り
ActionListener
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent event);
}
ActionEvent
Functional Interfaces
• 関数型インターフェイスには、いくつかのコアグループがある
Interface name Arguments Returns Example
Predicate<T> T boolean Has this album been
released yet?
Consumer<T> T void Printing out a value
Function<T, R> T R Get the name from
an Artist Object
Supplier<T> None T A factory method
UnaryOperator<T> T T Logical not(!)
BinaryOperator<T> (T, T) T Multiplying two
numbers(*)
Type Inference(型推論)
• Java7から、ダイヤモンド演算子を用いた型推論が可能
• メソッドの引数には型推論が使えなかったが、Java8から使えるよう
になった
Map<String, Integer> oldWordCounts = new HashMap<String, Integer>();
Map<String, Integer> diamondWordCounts = new HashMap<>();
useHashmap(new HashMap<>());
…
private void useHashmap(Map<String, String> values);
Type Inference
• ラムダ式を使った型推論
• パラメータの型は省略可能
• javacで戻り値の型がbooleanであるかチェックしてくれる
Predicate<Integer> atLeast5 = x -> x > 5;
public interface Predicate<T> {
boolean test(T t);
}
PredicateT boolean
Type Inference
• ラムダ式を使った型推論
• 後者では、型を指定していないため引数も戻り値の型も
java.lang.Objectとして判別される -> 足し算ができないと怒られる
/* 正常に動く */
BinaryOperator<Long> addLongs = (x, y) -> x + y;
/* コンパイルエラー */
BinaryOperator add = (x, y) -> x + y;
Key Points
• ラムダ式は、データであるかのように振る舞いを実装でき、メソッド
名を省略できる
• ラムダ式は、以下のように書くことができる
• 関数型インターフェイスは定義されている抽象メソッドが1つだけ
あるインターフェイスのことで、ラムダ式は、関数型インターフェイ
スに対して適用することができる
BinaryOperator<Integer> add = (x, y) -> x + y;

Java8 lambdas chapter1_2

  • 1.
  • 2.
    Table of Contents 1.Introduction • Why Did They Need To Change Java Again ? • What Is Functional Programming ? • Example Domain 2. Lambda Expressions • Your First Lambda Expression • How to Spot a Lambda in a Haystack • Using Values • Functional Interfaces • Type Inference • Key Points
  • 3.
    • マルチコア化で処理性能向上を目指す時代 • java.util.concurrentパッケージなどを使った並行処理には限界がある ⇒ ラムダ式を使った関数型プログラミングで簡潔、かつ強力な並行処理の実装 が書ける • 関数型言語の利点 • 可読性 • 保守性 • バグが少ない Why Did They Need To Change Java Again ?
  • 4.
    • 文字通り「関数」を使用したプログラミング • 入力した値に対して必ず同じ結果を返す •オブジェクト指向におけるメソッド(一連の手続きをまとめて名前を付けたもの) とは異なる • 関数の特徴 • 参照透過性 • ある関数に同じ入力値を与えれば、いつ評価しても必ず同じ値が得られる • 変数は一度定義したら二度と変えない(再代入操作で状態を書き換えない) • 第一級関数 • 変数に代入したり、別の関数の引数や戻り値になったりすることができる What Is Functional Programming ?
  • 5.
    Example Domain • 本全体を通して、例の提示には共通の問題領域として音楽が使 われる •要約は以下の通り • アーティスト – 曲を作る個人やグループ • トラック • 一つの曲 • アルバム • 複数のトラックの集合 • 音楽は関数型プログラミングの手法を説明する際に使われる
  • 6.
    Your First LambdaExpression • Swing(JavaのGUIライブラリ)でボタンをクリックした際の、匿名クラ スを用いたevent listenerの実装 • 不要な行が多い • 読みにくい button.addActionListener(new ActionListerner() { public void actionPerformed(ActionEvent event) { System.out.println("button clicked"); } });
  • 7.
    Your First LambdaExpression • ラムダ式を使用 • (メソッドの引数) -> (処理) の形で書ける • メソッド名や引数の型が省略できる button.addActionListener(event -> System.out.println("button clicked"));
  • 8.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 Runnable noArguments = () -> System.out.println("Hello world"); ActionListener oneArgument = event -> System.out.println("button clicked"); Runnable multiStatement = () -> { System.out.println("Hello"); System.out.pringln(" World"); }; BinaryOperator<Long> add = (x,y) -> x + y; BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
  • 9.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 引数がないときは()のように書ける。 戻り値の型はvoid Runnable noArguments = () -> System.out.println("Hello world");
  • 10.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 引数が一つのときは左辺の()を省略 できる。引数名は任意で指定可能 ActionListener oneArgument = event -> System.out.println("button clicked");
  • 11.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 処理が複数行に渡る場合は{}をつける Runnable multiStatement = () -> { System.out.println("Hello"); System.out.pringln(" World"); };
  • 12.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 処理が一行の場合、returnを 省略できる(x + y の結果を返す処理の実装) BinaryOperator<Long> add = (x,y) -> x + y;
  • 13.
    Your First LambdaExpression • ラムダ式を使った様々な実装例 引数の型は省略せずにも書ける BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
  • 14.
    Using Values • 匿名クラスでは、finalのローカル変数、引数が扱える •ラムダ式では、実質 finalのローカル変数、引数が扱える • (場合によってはfinalが可読性を損なうこともあるため) final String name = getUserName(); button.addActionListener(new ActionListerner(){ public void actionPerformed(ActionEvent event){ System.out.println("hi " + name); } }); String name = getUserName(); button.addActionListener(event -> System.out.println("hi " + name));
  • 15.
    Using Values • 下記の場合、nameが実質finalでないのでコンパイルエラーとなる String name = getUserName(); name = formatUserName(name); button.addActionListener(event -> System.out.println("hi " + name));
  • 16.
    Functional Interfaces • 関数型インターフェイスとは •定義されている抽象メソッドが1つだけあるインターフェイス • ラムダ式は、関数型インターフェイスに対して適用することができる • 今後は、関数型インターフェイスをダイアグラムで表現する • 関数に入っていく矢印は引数を、関数から出ていく矢印は戻り値の型を表す • 関数型インターフェイスとダイアグラムの例は下記の通り ActionListener public interface ActionListener extends EventListener { public void actionPerformed(ActionEvent event); } ActionEvent
  • 17.
    Functional Interfaces • 関数型インターフェイスには、いくつかのコアグループがある Interfacename Arguments Returns Example Predicate<T> T boolean Has this album been released yet? Consumer<T> T void Printing out a value Function<T, R> T R Get the name from an Artist Object Supplier<T> None T A factory method UnaryOperator<T> T T Logical not(!) BinaryOperator<T> (T, T) T Multiplying two numbers(*)
  • 18.
    Type Inference(型推論) • Java7から、ダイヤモンド演算子を用いた型推論が可能 •メソッドの引数には型推論が使えなかったが、Java8から使えるよう になった Map<String, Integer> oldWordCounts = new HashMap<String, Integer>(); Map<String, Integer> diamondWordCounts = new HashMap<>(); useHashmap(new HashMap<>()); … private void useHashmap(Map<String, String> values);
  • 19.
    Type Inference • ラムダ式を使った型推論 •パラメータの型は省略可能 • javacで戻り値の型がbooleanであるかチェックしてくれる Predicate<Integer> atLeast5 = x -> x > 5; public interface Predicate<T> { boolean test(T t); } PredicateT boolean
  • 20.
    Type Inference • ラムダ式を使った型推論 •後者では、型を指定していないため引数も戻り値の型も java.lang.Objectとして判別される -> 足し算ができないと怒られる /* 正常に動く */ BinaryOperator<Long> addLongs = (x, y) -> x + y; /* コンパイルエラー */ BinaryOperator add = (x, y) -> x + y;
  • 21.
    Key Points • ラムダ式は、データであるかのように振る舞いを実装でき、メソッド 名を省略できる •ラムダ式は、以下のように書くことができる • 関数型インターフェイスは定義されている抽象メソッドが1つだけ あるインターフェイスのことで、ラムダ式は、関数型インターフェイ スに対して適用することができる BinaryOperator<Integer> add = (x, y) -> x + y;