9ステップで理解するJavaとラムダ式入門

Javaとラムダ式を解説するイラストJava
この記事は約18分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaは、数あるプログラミング言語の中でも非常に人気が高く、多くのシステムで使用されています。

その魅力の一つに、ラムダ式という機能があります。

この記事では、Javaの基礎とその特徴、そしてラムダ式の基本的な使い方を、初心者の方にもわかりやすく解説していきます。

さらに、サンプルコードを交えながら、その応用や注意点についても詳しく見ていきます。

●Javaとは

Javaは、1990年代初頭にSun Microsystems(現Oracle Corporation)によって開発されたオブジェクト指向プログラミング言語です。

プラットフォームに依存しない特性を持ち、一度書いたコードをどの環境でも実行できるという特徴から、多くの開発者に愛されています。

○Javaの特徴

Javaには次のような特徴があります。

□オブジェクト指向

Javaはオブジェクト指向言語であり、データと処理を一つの単位として捉えることができます。

□プラットフォームに依存しない

JavaのコードはJava Virtual Machine(JVM)上で動作します。

これにより、異なるプラットフォームで同じJavaコードを実行できるため、再利用性が高くなっています。

□安全性

Javaにはガベージコレクションや例外処理など、多くの安全機構が備わっています。

□豊富なライブラリ

Javaには標準で多くのライブラリが提供されており、これを利用することで様々な機能を手軽に実装することができます。

○Javaの基本構文

Javaの基本的な構文を簡単に見ていきましょう。

ここでは、変数の宣言や演算、条件分岐、繰り返し処理について説明します。

□変数の宣言

Javaではデータ型を指定して変数を宣言します。

例えば、整数型の変数を宣言する場合は「int number = 10;」のように記述します。

□演算

Javaでは基本的な算術演算子(+、-、*、/)を使用して計算ができます。

このコードでは「int result = number + 5;」とすることで、変数numberに5を加算した結果をresultに代入します。

□条件分岐

if文を使用することで、条件に応じて異なる処理を行うことができます。

例えば、「if (number > 10) { System.out.println(“10より大きい”); }」のように記述することで、変数numberが10より大きい場合のみメッセージが出力されます。

□繰り返し処理

for文やwhile文を使用することで、特定の処理を繰り返し実行することができます。

for文の例として「for (int i = 0; i < 10; i++) { System.out.println(i); }」のように記述することで、0から9までの数字が順に出力されます。

●ラムダ式の基本

ラムダ式は、Java 8以降で導入された機能であり、匿名関数のような役割を果たします。

これにより、プログラムの記述がシンプルになり、読みやすいコードを作成できます。

特に、コレクションの処理を効率的に行う際に力を発揮します。

次に具体的な特性と例を表して説明します。

○ラムダ式の定義

ラムダ式は基本的に、(引数) -> { 処理 } という形式で記述します。

ここで、「->」はラムダ演算子と呼ばれ、引数と処理を区切る役割を果たします。引数は、0個以上指定できます。

また、処理の中には複数の文を記述できますが、一文のみの場合、波括弧は省略可能です。

具体的なラムダ式の定義の例を挙げます。

ここでは、二つの整数を受け取ってその和を出力するラムダ式を定義します。

(BiConsumer<Integer, Integer>) (x, y) -> {
  System.out.println(x + y);
};

このコードを実行すると、xとyの和がコンソールに出力されます。

説明の形式を参考にさせていただき、このコードではInteger型のxとyを引数として受け取り、それらの和をSystem.out.printlnで出力しています。

また、このコードを実行すると、指定したxとyの和がコンソールに表示される結果が得られます。

○ラムダ式の特徴

ラムダ式は数多くの特徴を持っていますが、次の点が特に注目されます。

  1. 簡潔な記述:ラムダ式を使用することで、複雑な処理を簡潔に記述できます。これにより、コードの読みやすさが向上します。
  2. 関数型プログラミングの導入:ラムダ式は関数型プログラミングの要素をJavaに導入します。これにより、プログラムの表現力が増加します。
  3. パフォーマンスの向上:ラムダ式は内部的に最適化されるため、高速な実行が期待できます。

ラムダ式のこれらの特徴を理解することは、Javaプログラミングの新たな道を開く第一歩と言えるでしょう。

また、ラムダ式を用いることで、繰り返しの処理やコレクションの操作がより簡単になります。

●ラムダ式の詳細な使い方

ラムダ式はJavaの機能の一つで、これを用いることでコードをより簡潔かつ柔軟に書くことが可能となります。

ここでは、ラムダ式の詳細な使い方について、基本的な書き方から引数と戻り値の取り扱い、さらにはサンプルコードを交えて解説いたします。

○基本的なラムダ式の書き方

ラムダ式の基本的な書き方は、パラメータと本体から構成されます。

パラメータは括弧内に指定し、本体はアロー(->)の右側に記述します。

このアローがラムダ式の中心的存在であると言えます。

例えば次のようなラムダ式があります。

(a, b) -> a + b

このコードは、aとbという2つのパラメータを受け取り、それらの和を返すラムダ式を表しています。

実際には、これをあるインターフェースのメソッドとして使用することで、機能的なプログラムを実装することが可能です。

○ラムダ式の引数と戻り値

ラムダ式の引数は、任意の数や型を取ることができます。

また、戻り値として任意の型を返すことも可能です。

ラムダ式内での処理は非常に幅広く、多岐にわたるプログラムを実装できます。

□サンプルコード1:ラムダ式の基本形

下記のサンプルコードでは、Runnableインターフェイスを用いたラムダ式の基本的な形を説明します。

このサンプルコードは、Runnableインターフェイスのrunメソッドをオーバーライドして、ラムダ式を使用しています。

Runnable runnable = () -> {
    System.out.println("ラムダ式を実行します");
};
runnable.run();

このコードを実行すると、コンソールに「ラムダ式を実行します」と表示されます。

ここでは無名インスタンスのrunメソッドをラムダ式でオーバーライドしているため、実行すると指定したメッセージが表示される結果になります。

□サンプルコード2:引数を取るラムダ式

引数を取るラムダ式の書き方も見ていきましょう。

この場合、BinaryOperatorインターフェイスを用いた例を説明します。

下記のコードは、BinaryOperatorインターフェイスのapplyメソッドをオーバーライドし、引数を受け取るラムダ式を表しています。

BinaryOperator<Integer> adder = (a, b) -> a + b;
Integer result = adder.apply(3, 4);
System.out.println("結果: " + result);

このコードを実行すると、コンソールに「結果: 7」と表示されます。

ここではaとbという2つのInteger型の引数を受け取り、それらの和を返すラムダ式を実装しています。

applyメソッドを使って3と4を引数として渡し、その和である7が返される結果になります。

□サンプルコード3:戻り値を返すラムダ式

戻り値を返すラムダ式についても解説します。

下記のコードは、Supplierインターフェイスを用いたラムダ式の例です。

このコードでは、Supplierインターフェイスのgetメソッドをオーバーライドし、戻り値を返すラムダ式を表しています。

Supplier<String> supplier = () -> "Hello, Lambda!";
String message = supplier.get();
System.out.println(message);

このコードを実行すると、コンソールに「Hello, Lambda!」と表示されます。

Supplierインターフェイスのgetメソッドをオーバーライドして文字列を返すラムダ式を実装しており、getメソッドを呼び出すことで指定したメッセージが表示される結果となります。

●ラムダ式の応用例

Javaのラムダ式はコードを簡潔にし、読みやすさと再利用性を向上させる優れた機能です。

さらに進んで、ラムダ式の応用例について詳しく解説いたします。

ラムダ式を使うと、コードが読みやすく、簡潔になります。

さらに、ラムダ式は関数型プログラミングの要素をJavaに取り入れ、コードの再利用性と可読性を高めます。

○ラムダ式とストリームAPI

Java8以降、ストリームAPIが導入されました。

ストリームAPIとラムダ式は非常に相性が良く、データの操作を直感的かつ簡潔に行えます。

ストリームAPIは、コレクションの要素に対する一連の操作をシーケンシャルかパラレルかを意識せずに行えるAPIです。

□サンプルコード4:リストの操作

ここでは、リスト内の各要素を2倍にして新しいリストを作成する簡単な例を紹介します。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        List<Integer> doubledNumbers = numbers.stream()
                .map(n -> n * 2)
                .collect(Collectors.toList());

        System.out.println(doubledNumbers); // 出力: [2, 4, 6, 8, 10]
    }
}

このコードを実行すると、numbersリスト内のすべての要素が2倍にされた新しいリストが出力されます。

このコードではストリームAPIのmapメソッドを使用し、ラムダ式n -> n * 2を使って各要素を2倍にしています。

□サンプルコード5:フィルタリングとマッピング

次に、リストから特定の条件を満たす要素だけを抽出し(フィルタリング)、さらに各要素に何らかの操作を行う(マッピング)例を紹介します。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");

        List<String> filteredAndMappedWords = words.stream()
                .filter(w -> w.length() > 5)
                .map(w -> w.toUpperCase())
                .collect(Collectors.toList());

        System.out.println(filteredAndMappedWords); // 出力: [BANANA, ELDERBERRY]
    }
}

このコードを実行すると、文字列の長さが5文字より多い単語だけが選択され、さらにそれらの単語が大文字に変換された新しいリストが生成されます。

このコードでは、ストリームAPIのfilterメソッドとmapメソッドをラムダ式と共に使用しています。

さらなる学習として、これらのメソッドの他にも多くの有用なメソッドがストリームAPIには存在しますので、是非その利用も考えてみてください。

○ラムダ式と関数型インターフェイス

Javaのプログラミング世界におけるラムダ式と関数型インターフェイスは、コードの簡潔さと可読性を高めるために非常に重要な要素となっております。

ここでは、その基本と使用方法を詳細に解説いたします。

まず、関数型インターフェイスとは、Java8から導入された概念であり、一つの抽象メソッドを持つインターフェイスのことを指します。

それによって、ラムダ式の導入が可能となりました。

ラムダ式は、匿名関数とも言える簡潔な表記方法で、関数型インターフェイスの抽象メソッドを実装する際に使います。

例えば、Runnable インターフェイスの実装を考えます。

下記のコードは、通常の匿名クラスを用いた実装方法です。

Runnable runnable = new Runnable(){
    @Override
    public void run(){
        System.out.println("匿名クラスを使用したRunnableの実装");
    }
};

次に、これをラムダ式を用いて簡略化します。

次のように書くことができます。

Runnable runnable = () -> {
    System.out.println("ラムダ式を使用したRunnableの実装");
};

このコードは、先のコードよりも簡潔になりました。

このコードを実行すると、コンソールに”ラムダ式を使用したRunnableの実装”と表示される結果を得られます。

このようにラムダ式を使用することで、よりシンプルかつ明瞭なコードを書くことが可能です。

□サンプルコード6:関数型インターフェイスの実装

関数型インターフェイスの実装に関して、詳しく見ていきましょう。

関数型インターフェイスを自身で定義し、それをラムダ式で実装する例をご紹介します。

まず、一つの抽象メソッドを持つ関数型インターフェイスを定義します。

@FunctionalInterface
interface Greeting {
    void sayHello(String name);
}

そして、この関数型インターフェイスをラムダ式で実装します。

Greeting greeting = (name) -> {
    System.out.println("こんにちは、" + name + "さん");
};

greeting.sayHello("山田");

このコードを実行すると、コンソールに”こんにちは、山田さん”と表示されます。

このように関数型インターフェイスとラムダ式を使用することで、簡潔かつ効率的なコードを書くことができます。

●ラムダ式の詳細な注意点

ラムダ式を使用する際には、いくつかの詳細な注意点があります。

まず、スコープと変数キャプチャについて、理解しておくことが非常に重要です。

次に、ラムダ式内での例外処理方法についても説明します。

それでは、次の見出しに従って説明を進めていきましょう。

○スコープと変数キャプチャ

ラムダ式のスコープとは、ラムダ式がアクセスできる変数の範囲を指します。

Javaでは、ラムダ式内から外部のローカル変数にアクセスする際には、その変数が事実上のfinal(つまり、変更されない)であるか、またはfinal変数である必要があります。

また、変数キャプチャとは、ラムダ式がその外部スコープの変数をキャプチャ(つまり、アクセスや利用)することを言います。

ここでは、変数キャプチャの一例をサンプルコードを通じて解説いたします。

□サンプルコード7: 例外処理とラムダ式

Javaのラムダ式内で例外処理を行う場合、少し注意が必要です。

通常のメソッドと異なり、ラムダ式内ではチェック例外が発生した場合、その例外を再スローすることができません。

しかし、次のような方法で、この問題を解決することが可能です。

下記のサンプルコードでは、ラムダ式内での例外処理の方法を表しています。

このコードを実行すると、例外が捕捉され、カスタムメッセージが表示されます。

List<String> list = Arrays.asList("a", "b", "c");
try {
    list.forEach(item -> {
        if ("b".equals(item)) {
            throw new RuntimeException("例外が発生しました");
        }
        System.out.println(item);
    });
} catch (RuntimeException e) {
    System.err.println(e.getMessage());
}

このコードでは、ListのforEachメソッドを使ってリストの各要素にアクセスしています。

if文で条件を満たす要素が見つかった場合、RuntimeExceptionをスローします。

このRuntimeExceptionは、外部のtry-catchブロックで捕捉され、カスタムメッセージがコンソールに表示されます。

このような流れでコードが進行すると、次の出力結果が得られます。

a
例外が発生しました

このコードサンプルはラムダ式内での例外処理方法を表しており、特定の条件下でRuntimeExceptionをスローし、それを外側のtry-catchブロックで捕捉する構造を取っています。

これにより、ラムダ式内での例外処理が可能となります。

●ラムダ式の詳細なカスタマイズ方法

ラムダ式はJavaの強力な機能の1つであり、コードの読みやすさと再利用性を向上させることができます。

この部分では、ラムダ式を更に詳細にカスタマイズする方法を超絶詳細に解説します。

○メソッド参照

メソッド参照は、ラムダ式のさらなる簡略化を可能にするJavaの機能です。

具体的な使用方法としては、ラムダ式内で行われる操作がすでに存在するメソッドによって実行できる場合、そのメソッドを直接参照することができます。

ここでは、それをどのように実行するかについての具体例を提供します。

□サンプルコード8:メソッド参照の利用

import java.util.List;
import java.util.stream.Collectors;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List<String> words = List.of("apple", "banana", "cherry");

        // ラムダ式を用いた方法
        List<String> upperCaseWordsLambda = words.stream()
                .map(word -> word.toUpperCase())
                .collect(Collectors.toList());

        // メソッド参照を用いた方法
        List<String> upperCaseWordsMethodRef = words.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());

        System.out.println(upperCaseWordsLambda);
        System.out.println(upperCaseWordsMethodRef);
    }
}

このコードでは、文字列のリストを作成し、それを大文字に変換して新しいリストに収集します。

上部の例はラムダ式を使用しており、下部の例は同じ操作をメソッド参照を使って行っています。

このコードを実行すると、出力結果は次のようになります。

[APPLE, BANANA, CHERRY]
[APPLE, BANANA, CHERRY]

○ラムダ式のテスト

ラムダ式のテストは非常に重要です。

テストを行うことで、コードが期待通りに動作することを確認できます。

また、将来的にコードに変更が加えられた場合に、その変更が何か問題を引き起こさないことを保証するためにも、テストは不可欠です。

この部分では、ラムダ式のテスト方法について詳しく説明します。

□サンプルコード9:ラムダ式のテスト

import org.junit.jupiter.api.Test;
import java.util.function.Predicate;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class LambdaTest {
    @Test
    public void testLambda() {
        Predicate<String> isLongerThanFive = str -> str.length() > 5;

        assertTrue(isLongerThanFive.test("abcdefg"));
        assertFalse(isLongerThanFive.test("abcd"));
    }
}

このコードでは、文字列が5文字より長いかどうかを判断するラムダ式をテストしています。

assertTrueassertFalseを使用して、ラムダ式が正しく動作していることを確認します。

このコードを実行すると、テストは正常にパスします。これにより、ラムダ式が正確に機能していることが表されます。

まとめ

Javaとラムダ式の基本から応用まで、この記事を通じてご紹介してまいりました。

今回の記事では、初心者でもスムーズに理解できるよう、9ステップでJavaとラムダ式の利用方法を解説してまいりました。

Javaとラムダ式の学習は、一度に全てを理解しようとせず、一歩ずつ進めていくことが重要です。

ラムダ式は初めは複雑に感じるかもしれませんが、基本的な構文から始めて、徐々に応用例へと進んでいくことで、スムーズに学習を進めることができます。

質問やコメントがあれば、お気軽にどうぞ。