0Pricing
Java Academy · レッスン

Optional の変換:map と flatMap

map と flatMap で変換を連鎖させ、null チェックなしで値を処理します。

「Optional の変換:map と flatMap」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

Optionalの変換: mapとflatMap

map()は、値が存在する場合にOptional内の値を変換します。flatMap()は、変換処理自体がOptionalを返す場合に、Optionalの入れ子を防ぎます。

map: 値の変換

map(Function)は、値が存在する場合にその値へ関数を適用し、結果を新しいOptionalでラップします。元のOptionalが空の場合は空を返します。

import java.util.Optional;

Optional<String> name = Optional.of("alice");

Optional<String> upper = name.map(String::toUpperCase);
System.out.println(upper.get()); // ALICE

Optional<Integer> length = name.map(String::length);
System.out.println(length.get()); // 5

// Empty in → empty out
Optional<String> empty = Optional.<String>empty().map(String::toUpperCase);
System.out.println(empty.isPresent()); // false

map呼び出しの連結

複数のmap呼び出しを連結すると、入れ子になったnullチェックなしで変換をきれいに組み立てられます。

import java.util.Optional;

record Address(String city, String country) {}
record User(String name, Address address) {}

User user = new User("Alice", new Address("New York", "US"));

// Chain of maps — safe even if any step returns null
Optional<String> city = Optional.ofNullable(user)
    .map(User::address)
    .map(Address::city)
    .map(String::toUpperCase);

System.out.println(city.orElse("Unknown")); // NEW YORK

flatMap: Optional<Optional>の回避

マッピング関数がOptionalを返す場合は、flatMapを使用して、入れ子になったOptional<Optional>ではなく、フラットなOptionalを維持します。

import java.util.Optional;

record User(String name, Optional<String> email) {}

User u = new User("Bob", Optional.of("bob@example.com"));

// map returns Optional<Optional<String>> — ugly!
Optional<Optional<String>> nested = Optional.of(u).map(User::email);

// flatMap flattens: Optional<String>
Optional<String> flat = Optional.of(u).flatMap(User::email);
System.out.println(flat.get()); // bob@example.com

実践的なflatMap: リポジトリーの連結

よくあるパターンとして、各処理がOptionalを返すリポジトリー検索を連結します。

import java.util.Optional;

record Order(long id, long userId, double total) {}
record User(long id, String name, String email) {}

static Optional<Order> findOrder(long orderId) {
    return orderId == 1 ? Optional.of(new Order(1, 42, 99.99)) : Optional.empty();
}
static Optional<User> findUser(long userId) {
    return userId == 42 ? Optional.of(new User(42, "Alice", "a@co.com")) : Optional.empty();
}

Optional<String> email = findOrder(1)
    .flatMap(o -> findUser(o.userId()))
    .map(User::email);

System.out.println(email.orElse("Not found")); // a@co.com

mapとflatMapのまとめ

mapとflatMapの使い分け:

  • 関数が通常の値(String、Integer)を返す場合はmapを使用します
  • 関数がOptionalを返す場合はflatMapを使用します
import java.util.Optional;

// map: T → R
Optional.of("hello").map(String::toUpperCase);       // Optional<String>
Optional.of("42").map(Integer::parseInt);             // Optional<Integer>

// flatMap: T → Optional<R>
Optional.of("42").flatMap(s -> {
    try { return Optional.of(Integer.parseInt(s)); }
    catch (NumberFormatException e) { return Optional.empty(); }
}); // Optional<Integer> (not Optional<Optional<Integer>>)

flatMapを使った安全な解析

便利なパターンとして、失敗する可能性のある危険な処理を、flatMapを使ってOptionalでラップします。

import java.util.Optional;

static Optional<Integer> tryParseInt(String s) {
    try { return Optional.of(Integer.parseInt(s)); }
    catch (NumberFormatException e) { return Optional.empty(); }
}

Optional<String> input = Optional.of("123");
Optional<Integer> parsed = input.flatMap(JavaOptional::tryParseInt);
System.out.println(parsed.map(n -> n * 2).orElse(-1)); // 246

Optional<String> bad = Optional.of("abc");
Optional<Integer> failed = bad.flatMap(JavaOptional::tryParseInt);
System.out.println(failed.orElse(-1)); // -1

Optionalの収集

Optionalのストリームをフィルタリングしてmapを適用し、値が存在するものだけを収集します。

import java.util.*;
import java.util.stream.*;

List<String> inputs = List.of("10", "abc", "25", "nope", "7");

List<Integer> numbers = inputs.stream()
    .flatMap(s -> {
        try { return Stream.of(Integer.parseInt(s)); }
        catch (NumberFormatException e) { return Stream.empty(); }
    })
    .collect(Collectors.toList());

System.out.println(numbers); // [10, 25, 7]

入れ子になったオブジェクトの走査

mapとflatMapを使うと、煩雑なnullチェックなしで、深いオブジェクトグラフを安全に走査できます。

import java.util.Optional;

record Company(String name, Optional<Address> address) {}
record Address(String city, Optional<String> zipCode) {}

Company company = new Company(
    "Acme Corp",
    Optional.of(new Address("Austin", Optional.of("78701")))
);

String zip = Optional.of(company)
    .flatMap(Company::address)
    .flatMap(Address::zipCode)
    .orElse("N/A");

System.out.println(zip); // 78701

型変換に使うmap

mapはOptionalの値の型変換に適しています。たとえば、解析、フォーマット、サブフィールドの抽出などに使えます。

import java.util.Optional;
import java.time.LocalDate;

// Parse a date from String safely
static Optional<LocalDate> parseDate(String s) {
    try { return Optional.of(LocalDate.parse(s)); }
    catch (Exception e) { return Optional.empty(); }
}

Optional<String> dateStr = Optional.of("2024-06-15");
Optional<Integer> year = dateStr
    .flatMap(JavaOptional::parseDate)
    .map(LocalDate::getYear);

System.out.println(year.orElse(-1)); // 2024

パイプラインの構築

filter、map、flatMapを組み合わせると、明示的なnullチェックなしで各ステップの値の不在を処理できる、表現力の高いデータパイプラインを構築できます。

import java.util.Optional;

record Product(String sku, String category, boolean inStock, double price) {}

static Optional<Product> findProduct(String sku) {
    if ("LAPTOP-1".equals(sku))
        return Optional.of(new Product("LAPTOP-1", "Electronics", true, 999.99));
    return Optional.empty();
}

Optional<String> priceTag = findProduct("LAPTOP-1")
    .filter(Product::inStock)
    .filter(p -> p.price() < 2000)
    .map(p -> String.format("%s: $%.2f", p.sku(), p.price()));

System.out.println(priceTag.orElse("Not available")); // LAPTOP-1: $999.99

クイックチェック

Optionalに対してmapではなくflatMapを使用するのは、どのような場合ですか。

まとめ: Optionalの変換: mapとflatMap

要点:

  • map()は値が存在する場合に変換し、結果をOptionalでラップします
  • flatMap()はOptionalを返す関数に使用し、Optionalの入れ子を防ぎます
  • 複数のmapを連結すると、nullチェックなしで複数段階の変換を実行できます
  • Optionalを返すリポジトリーやサービスの呼び出しを連結するにはflatMapを使用します
  • filter + map + flatMapを組み合わせて、null安全なデータパイプラインを構築します
  • flatMap Optional::streamを使うと、Optionalをストリームパイプラインに組み込めます

よくある質問

「Optional の変換:map と flatMap」レッスンは無料ですか?

はい。「Optional の変換:map と flatMap」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「Optional の変換:map と flatMap」で何を学びますか?

map と flatMap で変換を連鎖させ、null チェックなしで値を処理します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「Optional の変換:map と flatMap」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Optional が存在する理由
  2. Optional の作成と確認
  3. Optional の変換:map と flatMap
  4. Optional のベストプラクティス
← Java Academyに戻る