インターフェースの応用とLambda
このレッスンでは、インターフェースの高度な機能とLambda式を学び、コードをより簡潔にします。
インターフェースのデフォルトメソッド
Java 8では、インターフェースがメソッド本体を持てるようにするデフォルトメソッドが導入されました。
構文
JAVA
public interface MyInterface {
// 抽象メソッド
void abstractMethod();
// デフォルトメソッド
default void defaultMethod() {
System.out.println("デフォルト実装");
}
}
例:デフォルトメソッド
JAVA
public interface Vehicle {
void start();
default void horn() {
System.out.println("ビープ!");
}
default void stop() {
System.out.println("車両停止");
}
}
public class Car implements Vehicle {
@Override
public void start() {
System.out.println("車が起動");
}
// デフォルトメソッドをオプションでオーバーライド可能
@Override
public void horn() {
System.out.println("クラクション!");
}
}
public class DefaultMethodDemo {
public static void main(String[] args) {
Car car = new Car();
car.start(); // 車が起動
car.horn(); // クラクション!(オーバーライドされたメソッド)
car.stop(); // 車車両停止(インターフェースのデフォルト)
}
}
インターフェースの静的メソッド
Java 8では、インターフェース名を通じて直接呼び出される静的メソッドが導入されました。
JAVA
public interface MathUtils {
static int add(int a, int b) {
return a + b;
}
static int multiply(int a, int b) {
return a * b;
}
}
public class StaticMethodDemo {
public static void main(String[] args) {
System.out.println(MathUtils.add(3, 5)); // 8
System.out.println(MathUtils.multiply(3, 5)); // 15
}
}
関数型インターフェース
抽象メソッドが1つだけのインターフェースは、Lambda式で実装できます。
@FunctionalInterfaceアノテーション
JAVA
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
一般的な関数型インターフェース
| インターフェース | メソッド | 説明 |
|---|---|---|
Predicate<T> |
boolean test(T t) |
条件をテスト |
Function<T,R> |
R apply(T t) |
入力を出力に変換 |
Consumer<T> |
void accept(T t) |
入力を消費 |
Supplier<T> |
T get() |
出力を提供 |
Lambda式
Lambdaは無名関数の短縮形で、Java 8で導入されました。
構文
JAVA
(パラメータ) -> { 本体 }
例:Lambda
JAVA
// 従来の方法
Calculator add = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Lambda式
Calculator add = (a, b) -> a + b;
// 呼び出し
int result = add.calculate(3, 5); // 8
さまざまなLambda形式
JAVA
// パラメータなし
Runnable r = () -> System.out.println("Hello");
// 1つのパラメータ
Consumer<String> print = s -> System.out.println(s);
// 複数のパラメータ
Comparator<String> comp = (a, b) -> a.length() - b.length();
// 複数行の本体
Function<String, String> upper = s -> {
String result = s.trim();
return result.toUpperCase();
};
例:Lambdaの使用
JAVA
import java.util.Arrays;
import java.util.List;
import java.util.function.*;
public class LambdaDemo {
public static void main(String[] args) {
// Predicate:条件をテスト
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(7)); // false
// Function:変換
Function<String, Integer> length = s -> s.length();
System.out.println(length.apply("Hello")); // 5
// Consumer:消費
Consumer<String> print = s -> System.out.println("出力: " + s);
print.accept("Java"); // 出力: Java
// Supplier:提供
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
}
}
Lambdaとコレクション
Lambdaにより、コレクション操作がより簡潔になります。
例:反復
JAVA
import java.util.Arrays;
import java.util.List;
public class LambdaCollection {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 従来の方法
for (String name : names) {
System.out.println(name);
}
// Lambda方法
names.forEach(name -> System.out.println(name));
// メソッド参照(より簡潔)
names.forEach(System.out::println);
}
}
例:ソート
JAVA
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LambdaSort {
public static void main(String[] args) {
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
// 従来の方法
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
// Lambda方法
names.sort((a, b) -> a.compareTo(b));
// メソッド参照
names.sort(String::compareTo);
System.out.println(names); // [Alice, Bob, Charlie]
}
}
メソッド参照
メソッド参照はLambda式の短縮形です。
4種類のメソッド参照
| タイプ | 構文 | 例 |
|---|---|---|
| 静的メソッド | クラス名::静的メソッド |
Math::abs |
| インスタンスメソッド | オブジェクト::インスタンスメソッド |
System.out::println |
| 特定クラスのインスタンスメソッド | クラス名::インスタンスメソッド |
String::length |
| コンストラクタ | クラス名::new |
ArrayList::new |
例:メソッド参照
JAVA
import java.util.Arrays;
import java.util.List;
import java.util.function.*;
public class MethodRefDemo {
public static void main(String[] args) {
// 静的メソッド参照
Function<Integer, Integer> abs = Math::abs;
System.out.println(abs.apply(-5)); // 5
// インスタンスメソッド参照
Consumer<String> print = System.out::println;
print.accept("Hello"); // Hello
// 特定クラスのインスタンスメソッド参照
Function<String, Integer> length = String::length;
System.out.println(length.apply("Hello")); // 5
// コンストラクタ参照
Supplier<List<String>> listFactory = ArrayList::new;
List<String> list = listFactory.get();
}
}
包括的な例
JAVA
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaPractice {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 偶数をフィルタリング
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println("偶数: " + evens); // [2, 4, 6, 8, 10]
// 二乗
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("二乗: " + squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// 合計
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println("合計: " + sum); // 55
// 最大値
int max = numbers.stream()
.reduce(Integer::max)
.orElse(0);
System.out.println("最大値: " + max); // 10
}
}
❓ よくある質問
Q Lambdaと無名内部クラスの違いは何ですか?
A Lambdaはより簡潔ですが、関数型インターフェースでのみ機能します。無名内部クラスは任意のインターフェースまたはクラスで動作します。
Q いつLambdaを使用すべきですか?
A 関数型インターフェースを実装するとき、特にコレクション操作やイベント処理に使用します。
Q メソッド参照とLambdaのどちらを選ぶべきですか?
A Lambdaが既存のメソッドを呼び出すだけの場合、簡潔さのためにメソッド参照を使用してください。
📖 まとめ
- インターフェースのデフォルトメソッド:Java 8で導入、インターフェースがメソッド本体を持てる
- インターフェースの静的メソッド:インターフェース名を通じて直接呼び出し
- 関数型インターフェース:抽象メソッドが1つだけのインターフェース
- Lambda式:無名関数の短縮形
- メソッド参照:Lambdaの短縮形
📝 演習
- Lambda練習: Lambdaを使用して文字列を大文字に変換、長さを取得、空かどうかを確認
- コレクション操作: Lambdaを使用してコレクションをフィルタリング、変換、ソート
- カスタム関数型インターフェース: 数学演算インターフェースを定義し、Lambdaで加算/減算/乗算/除算を実装
次のレッスン
次のレッスンでは、列挙型と内部クラスを学びます — Javaの特殊なクラス。



