0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Java Silver確実合格を目指すカレンダーAdvent Calendar 2024

Day 18

【Java】ラムダ式周りについて解説

Last updated at Posted at 2024-12-17

初めに

Javaでは関数インタフェースがあるが、ラムダ式を使うとかなり簡単に処理を書くことができる。ラムダ式ではいくつかルールがある。またラムダ式や関数インタフェースの変換についても理解しておこう。

ラムダ式で使う変数は実質finalでないとエラー

Java(Main.java)
import java.util.function.Supplier;

public class Main {
	public static void main(String[] args) {
		int i = 0;
		Supplier<Integer> foo = () -> i;
		i++;
		
		System.out.println(foo.get());
	}
}

結果

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	Local variable i defined in an enclosing scope must be final or effectively final

	at Main.main(Main.java:6)

ラムダ式を囲むブロック(今回はmainクラス)の中で宣言されたローカル変数をラムダ式内で利用する場合、その変数がfinalで宣言されているか、実質finalでなければいけない。そのため変数iをインクリメントするとエラーになる。
以下のようにi++をコメントアウトするとエラーは発生しない。

Java(Main.java)
import java.util.function.Supplier;

public class Main {
	public static void main(String[] args) {
		int i = 0;
		Supplier<Integer> foo = () -> i;
//		i++;
		
		System.out.println(foo.get());
	}
}

結果

0

ラムダ式で使う変数はローカル変数とかぶるとエラー

以下のようにラムダ式内で使う変数numとローカル変数numは変数名がかぶっているのでエラー

Java(Main.java)
import java.util.function.Consumer;

public class Main {
	public static void main(String[] args) {
		int num = 1;
		Consumer<Integer> count = (num) -> {
				System.out.println(num + 1);
		};
		count.accept(10);
	}
}

関数インタフェースからラムダ式への変換

Functionインタフェースと匿名クラスを使用してソースを記述すると以下のようになる。

Java(Main.java)
import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		String str = new Function<String,String>(){
			public String apply(String str) {
				return "Hello" + str;
			}
		}.apply("suzuki");
		System.out.println(str);
	}
}

結果

Hellosuzuki

しかしこれだとかなり長くて冗長である。これをさらに短い形にしたのがラムダ式である。

Java(Main.java)
import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		Function<String,String> hello = (String str) -> {
			return "Hello" + str;
		};
		System.out.println(hello.apply("suzuki"));
	}
}

ここからさらに省略することもできる。以下の条件に当てはまるか確認しよう。

①引数の型が推論できるか
Functionで明記しているため、strはString型だと推論できる。その場合以下のように引数の型を省略できる。

Java(Main.java)
 import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		Function<String,String> hello = (str) -> {
			return "Hello" + str;
		};
		System.out.println(hello.apply("suzuki"));
	}
}

②引数が1つかどうか
引数が1つの場合、引数の()を省略できる。

Java(Main.java)
 import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		Function<String,String> hello = str -> {
			return "Hello" + str;
		};
		System.out.println(hello.apply("suzuki"));
	}
}

③処理が1文かどうか
処理が1文の場合、処理文の{}を省略できる。さらにreturnも省略可能。

Java(Main.java)
 import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		Function<String,String> hello = (str) -> "Hello" + str;
		System.out.println(hello.apply("suzuki"));
	}
}

メソッド参照

上記のラムダ式をメソッド参照で呼び出す場合はクラス名::メソッド名または参照型変数::メソッド名でy日だし、関数インタフェースに代入することが可能。イメージとしてはメソッド自体を変数に入れて、それを使う感じ。またメソッドの後ろに()はつけないので注意。

Java(Main.java)
import java.util.function.Function;

public class Main {
	public static void main(String[] args) {
		Function<String,String> hello = Main::sayHello;

		System.out.println(hello.apply("suzuki"));
	}
	public static String sayHello(String str) {
		return "Hello" + str;
	}
}

(復習)例を用いて関数インタフェースからラムダ式、メソッド参照に置き変える

①関数インタフェース

Java(Main.java)
import java.util.List;
import java.util.function.Consumer;

public class Main {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3);
		Consumer<Integer> print = new Consumer<Integer>() {
			public void accept(Integer x) {
				System.out.println(x);
			}
		};
		list.forEach(print);
	}
}

②ラムダ式

Java(Main.java)
import java.util.List;

public class Main {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3);
		list.forEach((x) -> System.out.println(x));
	}
}

③メソッド参照

Java(Main.java)
import java.util.List;
import java.util.function.Consumer;

public class Main {
	public static void main(String[] args) {
		List<Integer> list = List.of(1,2,3);
		Consumer<Integer> print = System.out::println;
		list.forEach(print);
	}
}

まとめ

  • ラムダ式で使う変数は実質final
  • ラムダ式で使う変数はローカル変数とかぶらないようにする
  • 関数インタフェースからラムダ式、メソッド参照へ変換可能
  • ラムダ式は条件に合致すれば省略できる部分がある
  • メソッド参照はメソッド名の後ろに()をつけない
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?