Gumma_de_Sharoushiのブログ

群馬で社労士として開業をめざします。→開業しました。

ラムダ式について【java】

私が最近習ったjavaラムダ式の説明が大変分かりやすいものだったので紹介します。

 

第1段階 ふつうの書き方

SelectGreeting.java


package lamda;

import java.util.*;

public class SelectGreeting {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		Scanner sc = new Scanner(System.in);
		System.out.println("今何時?:");
		int hour = sc.nextInt();
		
		if(hour >= 5 && hour <=10) {
			System.out.println("おはようございます");
		}else if(hour >=11 && hour <= 16) {
			System.out.println("こんにちは");
		}else if(hour >= 17 && hour <=22) {
			System.out.print("こんばんは");
		}else {
			System.out.println("どうしたんですか?こんな時間に");
		}
	}
}

 

初心者が書くような、べたなコードです。

 

ユーザに数字を入力してもらい、if文で場合分けしています。

 

数字によってコンソールにあいさつの言葉が表示されます。

 

このコードの難点は、System.out.printlnの中身を見るまで、何をしたいかが分からないことです。

 

 

第2段階 なるべくメソッドを使う

SelectGreeting2.java


package lamda;

import java.util.*;
/*
 * 「メソッド名」で「処理内容」を表すように
 * SelectGreetingクラスを改良
 */
public class SelectGreeting2 {

	private void morning() {
		System.out.println("おはようございます");
	}
	
	private void afternoon() {
		System.out.println("こんにちは");
	}
	private  void evening() {
		System.out.print("こんばんは");
	}
	
	private void midnight() {
		System.out.println("どうしたんですか?こんな時間に");
	}
	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		Scanner sc = new Scanner(System.in);
		System.out.println("今何時?:");
		int hour = sc.nextInt();
		
		SelectGreeting2 greet = new SelectGreeting2();
		
		if(hour >= 5 && hour <=10) {
			greet.morning();
		}else if(hour >=11 && hour <= 16) {
			greet.afternoon();
		}else if(hour >= 17 && hour <=22) {
			greet.evening();
		}else {
			greet.midnight();
		}
	}
}

 

このコードではmorning()メソッド、afternoon()メソッド、evening()メソッドを実装してみました。

 

これにより、第1段階よりだいぶやりたいことがくっきりしてきました。

 

メソッドには名前がついていますから、処理の内容がメソッド名を見るだけで分かるのです。

 

このコードではメソッドに適正な名前を付けることが重要となります。

 

例えばmorning()メソッドをmethod1()とか、afternoon()メソッドをmethod2()とかにしたらダメです。

 

 

 

第3段階 匿名クラスを使う

まず準備。

SAMインターフェースを用意します。

 

Greeting.java


package lamda;
/*
 * SAM(Single Abstract Method)インターフェース
 * ※関数型インターフェースとも呼ぶ
 */
public interface Greeting {
	void greet();
}

 

SAMというのは、一個だけの空っぽのメソッドをもったインターフェースです。

 

メソッド名は重要です。

 

ここで分かりやすい名前をどうつけるかが大切です。

 

今回はgreetとなりました。

 

つづいて、このインターフェースを匿名クラスで実装していきます。

 

SelectGreeting3.java


package lamda;

import java.util.*;
/*
 * 「匿名クラス」を利用して「処理内容」と「変数」を対応させるように
 * SelectGreeting2クラスを改良
 */
public class SelectGreeting3 {


	public static void main(String[] args) {
		
		Greeting morning = new Greeting() {
			@Override
			public void greet() {
				// TODO 自動生成されたメソッド・スタブ
				System.out.println("おはようございます");
			}
			
		};
		
		Greeting afternoon = new Greeting() {

			@Override
			public void greet() {
				// TODO 自動生成されたメソッド・スタブ
				System.out.println("こんにちは");
			}
			
		};
		
		Greeting evening = new Greeting() {

			@Override
			public void greet() {
				// TODO 自動生成されたメソッド・スタブ
				System.out.print("こんばんは");
			}
			
		};
		
		Greeting midnight = new Greeting() {

			@Override
			public void greet() {
				// TODO 自動生成されたメソッド・スタブ
				System.out.println("どうしたんですか?こんな時間に");
			}
			
		};
		Scanner sc = new Scanner(System.in);
		System.out.println("今何時?:");
		int hour = sc.nextInt();
		
		if(hour >= 5 && hour <=10) {
			morning.greet();
		}else if(hour >=11 && hour <= 16) {
			afternoon.greet();
		}else if(hour >= 17 && hour <=22) {
			evening.greet();
		}else {
			midnight.greet();
		}
	}
}

 

匿名クラスというのは、一時的な、かりそめの、そのときだけのクラスという使い方のことです。

 

実装と同時に実体化、インスタンス化していまして、詳しいことはそっち系の本を読んでください。

 

私は使うことはできるけど、解説するほど詳しくは知りません(すみません)。

 

第2弾と違うのは、greet.morning()がmorning.greet()となったところです。

 

どちらも分かりやすさにそれほど差はないです。

 

しかし、第3弾の特徴は、より開発工程に沿った形になっていることです。

 

最初にインターフェースを用意します。この段階では具体的な内容は実装していません。

 

次に、インターフェースを実装します。ここではじめて変数を分かりやすい名称にしています。

 

こうすることで可読性がぐっと上がっています。

 

第2弾では最初から分かりやすい命名をする必要がありました。メソッドをコーディングする段階でmorning、afternoon、eveningという名称を考える必要がありました。

 

第3弾ではインターフェースの段階ではgreetというメソッド名だけを考えればよく、実際の実装のコーディングの段階で初めてmornig、afternoon、eveningというより具体的な名称を考えています。

 

最初はざっくり → 次のフェーズでより細かく

 

こういう流れは、設計的にも理解しやすく、実装もしやすくなります。

 

 

第4段階 ラムダ式

ここでは、いよいよラムダ式の登場です。

 

第3段階における匿名クラスの部分をラムダ式に書き換えます。

 

ラムダ式というのは、匿名クラスの当たり前の部分を極力削除していったコードです。

 

匿名クラス

                Greeting morning = new Greeting() {

                        @Override

                        public void greet() {

                                // TODO 自動生成されたメソッド・スタブ

                                System. out .println("おはようございます");

                        }

                };

たとえば、上記の赤文字部分は当たり前ですよね。

変数morningの型宣言がGreeting型であることが分かっていますので、わざわざ赤文字部分は書かなくても分かるはずです。

 

だから、とってしまいます(ついでに、newも当たり前なのでとります)

 

匿名クラスから一部をとった

                Greeting morning =                   {

                        @Override

                        public void greet() {

                                // TODO 自動生成されたメソッド・スタブ

                                System. out .println("おはようございます");

                        }

                };

ところで、Greetingインターフェースの中に、メソッドは一つしかないのでした。

 

SAMですから。

 

ということは、public void greetの部分も当たり前だということになります。

 

さらに当たり前の部分を探す

                Greeting morning =                  {

                        @Override

                        public void greet() {

                                // TODO 自動生成されたメソッド・スタブ

                                System. out .println("おはようございます");

                        }

                };

当たり前の部分はとってしまいましょう。

 

こうなります。

 

当たり前の部分を削った匿名クラス

                Greeting morning =                  {

                        @Override

                                                         () {

                                // TODO 自動生成されたメソッド・スタブ

                                System. out .println("おはようございます");

                        }

                };

 

アノテーション(@)やコメント(//)、{}も冗長な部分をとってしまいましょう。

 

こうなります。

 

無駄をとった匿名クラス(ほとんど原形をとどめていない)

                Greeting morning =                  

                                         

                                                        ()

                                                                                                    

                                System. out .println("おはようございます");

                         

                   

ここにラムダ式の目印である->(矢印)を付け加えると、ラムダ式の完成です。

 

ラムダ式の矢印を加える

                Greeting morning =                

                                         

                                                          ()->

                                                                                                    

                                System. out .println("おはようございます");

                         

                   

 

よけいな空白や改行を削除して整理して書いたのがこちらです。

 

ラムダ式

                Greeting morning =()->

                                System. out .println("おはようございます");

 

これでラムダ式の完成です。

 

これを他の変数にも適用したのがこちら。

 

SelectGreeting4.java


package lamda;

import java.util.*;
/*
 * 「ラムダ式」を利用して「処理内容」と「変数」を対応させ、
 * よりスッキリとしたコードに
 * SelectGreeting3クラスを改良
 */
public class SelectGreeting4 {


	public static void main(String[] args) {
		
		//ラムダ式によって、「処理内容」に直接、「変数名」がつけられた形にする
		Greeting morning = ()->
			System.out.println("おはようございます");
		
		Greeting afternoon = ()->
				System.out.println("こんにちは");
		
		Greeting evening = ()->
			System.out.print("こんばんは");
		
		Greeting midnight = ()->
			System.out.println("どうしたんですか?こんな時間に");
			
		Scanner sc = new Scanner(System.in);
		System.out.println("今何時?:");
		int hour = sc.nextInt();
		
		if(hour >= 5 && hour <=10) {
			morning.greet();
		}else if(hour >=11 && hour <= 16) {
			afternoon.greet();
		}else if(hour >= 17 && hour <=22) {
			evening.greet();
		}else {
			midnight.greet();
		}
	}
}

 

だいぶすっきりしたと思います。

 

また、第1段階のコードより第4段階のコードの方が、何をやっているか、人間が直感的に見て分かるようになっていると思います。

 

ラムダ式の問題点

 

ラムダ式はすっきりとしたコードになりますが、問題もあります。

 

慣れていないと何が何やらわからない点です。

 

今回は引数がないSAMでしたが、もし引数があるなら、このようになります。


findViewById(R.id.btnDL).setOnClickListener(v ->
        Toast.makeText(MainActivity.this, "こんにちは!!", Toast.LENGTH_SHORT).show());

 

これはAndroidアプリのボタンを押したときの動作を記述したコードです。

 

ボタンを押すとあいさつ文を表示(Toast)します。

 

setOnClickListenerの次に出現する謎の「v」。これが何かを知っているのは、このラムダ式がもともとは次のような匿名クラスだったことを知っている人だけです。

 


findViewById(R.id.btnList).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Toast.makeText(MainActivity.this, "こんにちは!!", Toast.LENGTH_SHORT).show();
    }
});

 

onClickメソッドの引数にView型の引数viewがあります。

 

ラムダ式ではこれを「v」と表示しているのです。

 

こんなの、初めての人にわかる訳がありませんね!?

 

という訳で、初心者は慣れるまでは匿名クラスで書きなさいと教わりました。

 

何度も何度も書いて、慣れてきたところでラムダ式に切り替えるとよいでしょうということでした。

 

 

 

この記事はjavaを学習する人のために書いていますが、著作権的に問題あるようなら削除するか非公開にします。権利者またはその関係者の方はコメントください。