1
/
5

【若手WEBエンジニア必見!】~社内勉強会~技術顧問の久保(jflute)さんによる、「匿名クラスとラムダ式」講義を実施して頂きました!

メンバーズキャリア採用広報担当の田中です!
今回は先日メンバーズキャリアで実施した、
WEBエンジニア向けの社内勉強会(有給研修)の様子をお届けします!

当社の技術顧問である久保 雅彦(@jflute)さんに
「匿名クラス&ラムダ式&Optional」をテーマに講義をしていただきました。

今回は、より分かりやすくお届けするために、実際に勉強会に参加したWEBエンジニアの方に
勉強会の内容を自分なりに整理してもらいましたので、そちらをご紹介します!!

研修テーマは「匿名クラス&ラムダ式&Optional」

匿名クラス&ラムダ式

問題:コールバックの中で呼び出し元のローカル変数を書き換えるとコンパイルエラーになるのはなぜ?

package console;

public class Test {
	public static void main(String[] args) {

		// mainのローカル変数
		Boolean mainFlg = false;
		
		// ️匿名クラス
		Hoge anonymous = new Hoge() {
			@Override
			public void print() {
				// ここでエラー
				mainFlg = true;
			}
		};
		anonymous.print();
	}

	public interface Hoge {
		void print();
	}
}

書き換え部分で以下のエラーが出ます
「Local variable mainFlg defined in an enclosing scope must be final or us final」

グーグル翻訳にかけてみると
「囲みスコープで定義されたローカル変数mainFlgはfinalまたはus finalでなければなりません」

上記を理解するために・・・
– 匿名(無名)クラスとは?
– ラムダ式とは?
– コールバックとは?


匿名(無名)クラスとは

一回しか利用しないクラスを定義&インスタンス作成します。

public static void main(String[] args) {

                // Hogeインターフェースを実装した匿名クラスのインスタンスを作成
		Hoge anonymous = new Hoge() {
			@Override
			public void print() {
				System.out.println("TEST1");
			}
		};
		anonymous.print();

	}

	public interface Hoge {
		void print();
}

出力結果:TEST1


ラムダとは

匿名クラスを簡単に書ける記法 (ひとまずそう捉えて良い)

java
package console;

public class Test {
	public static void main(String[] args) {
		// ラムダ式
		Hoge lambda = () -> System.out.println("TEST1");
		lambda.print();
	}

	public interface Hoge {
		void print();
	}
}

出力結果:TEST1

上記のように、匿名クラスのコードと同様の結果になります。
そのため、eclipseではクイックフィックス機能を利用することで相互に変換できます。

匿名クラスを理解できていると、ラムダ式がどのような動きをしているか理解しやすいのでセットで覚えたいですね。


コールバックとは

以下のコードの出力はどのようになるでしょうか?

public class Test {
	public static void main(String[] args) {
		
		System.out.println("TEST_A");
		
		// ラムダ式
		Hoge lambda = () -> System.out.println("TEST_B");
		
		System.out.println("TEST_C");
		
		lambda.print();
	}

	public interface Hoge {
		void print();
	}
}


実行すると、A→C→Bの順に出力されます。
これはBの実行がlambda.print();の時点で行われるためです。

以下のコードでも実行結果はA→C→B2となります。

public class Test {
	public static void main(String[] args) {

		System.out.println("TEST_A");

		// ラムダ式
		// Hoge lambda = () -> System.out.println("TEST_B");
		Hoge hogeImpl = new Hoge();

		System.out.println("TEST_C");

		// lambda.print();
		hogeImpl.print();
	}

	public interface Hoge {
		void print();
	}

}

class HogeImpl implements Test.Hoge {
	public HogeImpl() {
	}

	public void print() {
		System.out.println("TEST_B2");
	}
}


両者の違いは、匿名クラス(ラムダ式)でインスタンスを作成しているか、通常のクラス定義をしているかですが、この違いは”System.out.println(“TEST_B”)を記載する場所の違い”でもあります。

* ラムダ式の場合     = printメソッドの呼び出し元で記載
* 通常のクラス定義の場合 = printメソッドの呼び出し先で記載

前置きが長くなってしまいましたが、コールバックとは呼び出し元で記載した処理(関数オブジェクト)を別の処理内で動作させるための方法のようなものです。
ラムダ式や匿名クラスは、「インターフェースに定義したメソッドの実装を呼び出し元で定義&1回限り利用するクラス定義→インスタンス作成」することができます。

冒頭の問題:コールバックの中で呼び出し元のローカル変数を書き換えるとコンパイルエラーになるのはなぜ?

コールバックとして定義した処理をどのように利用するかは、呼び出し先の処理に委ねられています。複数回利用されたり、1回も利用されないこともあり得ます。
(上記のサンプルでは呼び出し元で、ラムダ式などによって作成したインスタンスから、print()を呼び出していましたが、呼び出さないことも可能)

呼び出し元のローカル変数をコールバック関数に含めた場合、ローカル変数がどのように扱われるかは、呼び出し先に委ねられることになってしまいます。
ローカル変数は、宣言したスコープの中でのみ利用されるべきであり、別の処理内で操作されることは避けるべきです。
そのため、コンパイルエラーとなります。

匿名クラスとラムダ式の動きを理解できていれば、コンパイルエラーになる理由がよく理解できると思います。

Optional(null安全)

データは getした際に、データが取得できることが保証されていないリソースの場合、getの結果が nullであることが想定されます。そのため、取得したデータが nullではないことをチェックする必要があります。

public class Test {
	public static void main(String[] args) {
		String hoge = getHoge();
		
		//nullだった場合は処理しない
		if(hoge == null) {
			return;
		}
	}
	
	static String getHoge() {
		return null;
	}
}

上記のように取得後にnullチェックをすることを徹底すればエラーは発生しません。が、人間がコーディングする以上ミスはありえます。

そこで、以下のようにOptional型でラップした型(ここではString)を返却するようにします。

import java.util.Optional;

public class Test {
	public static void main(String[] args) {
		String hoge = getHoge(); //ここでコンパイルエラー
		
		//nullだった場合は処理しない
		if(hoge == null) {
			return;
		}
	}
	
    //返却する型をOptionalでラップする
	static Optional getHoge() {
		return null;
	}
}

こうすることで、mainの呼び出し部分で型が合わないためコンパイルエラーになります。

したがって呼び出し側は、getHogeを利用する際に以下のように呼び出すことを強制されます。

public class Test {
	public static void main(String[] args) {
		Optional hoge = getHoge(); //Optionalで結果を受け取る
		
		//hogeがnullではない場合、コールバック関数を実行するOptional.ifPresentを利用し、アンラップする。
		hoge.ifPresent(h -> System.out.println(h));
	}
	
	static Optional getHoge() {
		//Optional.ofNullable(null);
		return Optional.ofNullable("nullではない");
	}
}

実行結果:nullではない

Optional.ifPresentはhogeがnullではない場合のみ、引数のコールバック関数を実行するメソッドです。

このように、呼び出し側にnullチェックを強制させることで、実行時にぬるぽでアプリケーションが落ちることを防止できます(コンパイル時にエラーに気づける)。

ちなみに、上記でgetHogeからOptional.ofNullable(null)が返却された場合、実行結果は何もありません。(hoge.ifPresentで引数のコールバック関数が実行されない)

バグをコンパイル時に見つけることができるOptionalは、コードの品質に直結するのでぜひ使いこなしたいですね。


信頼してもらえるエンジニアになるために

講義の予定時間が少し余ったため、エンジニアとして仕事をしていく上で大切な心構えをお話ししていただきました。その中でも特に「質問」についてのお話がとても印象深く、重要な事だと感じたので、
少しご紹介させていただきます。

質問についてのお話の中で私が重要だと感じた箇所は

  • 質問する際は、その背景も添えて。
  • 質問そのものが問題の本質であることが少ない
  • 質問される側は、気付きとなる情報があれば問題の本質から解決できることが多い

です。

詳しくはこちらをご覧下さい!

質問のコツその一: なんでその質問してるのか?も伝えよう - jfluteの日記
後輩「はさみ、どこかわかります?」 先輩「えっ、はさみ?  えーっと、誰も使ってなければあっちの棚の上かな」 後輩「ありがとうございます、さすが先輩!」 先輩「...」 次の日... 先輩「そいえば、はさみあった?」 後輩「えっと、まだいま探してます、徹夜で探してて」 先輩「いやいやいやいや、棚の上は?」 後輩「誰か使ってるみたいなので...誰かっての探してて」 ...
https://jflute.hatenadiary.jp/entry/20170611/askingway1

具体的な質問の仕方は、こちらが参考になるかと思います。

質問は恥ではないし役に立つ - Qiita
一年半SEとして働いてきた中で、私自身が苦手だと思っており、他人からもそのように評価されていたのが「質問の仕方」でした。 それが先日、他人から「質問の仕方がうまいね」と褒められることがあり、ようやく一人前の質問の仕方ができるようになっ...
https://qiita.com/seki_uk/items/4001423b3cd3db0dada7


ご登壇いただいた講師

今回ご登壇いただいた講師の久保 雅彦氏についてはこちらの紹介記事もご覧下さい!

メンキャリ技術顧問のご紹介|メンバーズキャリア
久保 雅彦氏|オープンソースプログラマー
https://www.memberscareer.co.jp/skillup/specialadvisers/detail/?p=558#post



株式会社メンバーズキャリアでは一緒に働く仲間を募集しています

サーバーサイドエンジニア
技術向上を支援!学び合うJava,ScalaエンジニアWanted
【デジタルビジネス運用支援事業】 当社は「デジタルクリエイター」を正社員で採用し、日々スキル向上ができる環境の中で、クライアント伴走支援というビジネスモデルをとっています。 UXデザイナー、データアナリスト、Webディレクター、Webエンジニアなど、多様なデジタルクリエイターが在籍しています。東証プライムに上場しているため設備や制度の整った部分と、デジタルクリエイターが主役であり挑戦を続けるベンチャー気質、どちらも感じられる会社です。
株式会社メンバーズ
Sales / Business Development
クリエイターと顧客に寄り添う人材ソリューション営業募集!
【デジタルビジネス運用支援事業】 当社は「デジタルクリエイター」を正社員で採用し、日々スキル向上ができる環境の中で、クライアント伴走支援というビジネスモデルをとっています。 UXデザイナー、データアナリスト、Webディレクター、Webエンジニアなど、多様なデジタルクリエイターが在籍しています。東証プライムに上場しているため設備や制度の整った部分と、デジタルクリエイターが主役であり挑戦を続けるベンチャー気質、どちらも感じられる会社です。
株式会社メンバーズ
UI/UXデザイナー
UXを向上!スキルアップをしたいUI/UXデザイナー大募集!
【デジタルビジネス運用支援事業】 当社は「デジタルクリエイター」を正社員で採用し、日々スキル向上ができる環境の中で、クライアント伴走支援というビジネスモデルをとっています。 UXデザイナー、データアナリスト、Webディレクター、Webエンジニアなど、多様なデジタルクリエイターが在籍しています。東証プライムに上場しているため設備や制度の整った部分と、デジタルクリエイターが主役であり挑戦を続けるベンチャー気質、どちらも感じられる会社です。
株式会社メンバーズ
フロントエンドエンジニア
最新フレームワークを駆使して開発したいフロントエンドエンジニア募集!
【デジタルビジネス運用支援事業】 当社は「デジタルクリエイター」を正社員で採用し、日々スキル向上ができる環境の中で、クライアント伴走支援というビジネスモデルをとっています。 UXデザイナー、データアナリスト、Webディレクター、Webエンジニアなど、多様なデジタルクリエイターが在籍しています。東証プライムに上場しているため設備や制度の整った部分と、デジタルクリエイターが主役であり挑戦を続けるベンチャー気質、どちらも感じられる会社です。
株式会社メンバーズ
デザイナー
20新卒:デザイナー/クリエイターとして成長したい!!その意欲を支えます
【デジタルビジネス運用支援事業】 当社は「デジタルクリエイター」を正社員で採用し、日々スキル向上ができる環境の中で、クライアント伴走支援というビジネスモデルをとっています。 UXデザイナー、データアナリスト、Webディレクター、Webエンジニアなど、多様なデジタルクリエイターが在籍しています。東証プライムに上場しているため設備や制度の整った部分と、デジタルクリエイターが主役であり挑戦を続けるベンチャー気質、どちらも感じられる会社です。
株式会社メンバーズ
株式会社メンバーズ's job postings
7 Likes
7 Likes

Weekly ranking

Show other rankings
Invitation from 株式会社メンバーズ
If this story triggered your interest, have a chat with the team?