コンテンツにスキップ

Java相互運用性

English | 日本語

このガイドでは、jvがJavaコード、ライブラリ、そしてより広いJavaエコシステムとどのように相互運用するかを説明します。

目次

  1. 概要
  2. jvからJavaを呼び出す
  3. 生成されるJavaコード
  4. 型マッピング
  5. null安全性統合
  6. コレクションとジェネリクス
  7. 例外処理
  8. アノテーション
  9. ベストプラクティス
  10. 共通パターン

概要

jvはJavaとのシームレスな相互運用性を持つよう設計されています:

  • ゼロランタイムオーバーヘッド: jvは追加ランタイムなしで純粋なJavaにコンパイル
  • 直接ライブラリアクセス: ラッパーなしであらゆるJavaライブラリを使用
  • 読みやすい出力: 生成されるJavaは手書きコードのように見える
  • 標準準拠: 生成されるコードはJava規約に従う

jvからJavaを呼び出す

基本的なJavaライブラリ使用

Javaクラスとメソッドはjvで直接使用できます:

import java.util.ArrayList
import java.util.HashMap
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

fun demonstrateJavaInterop() {
    // Javaコレクションの使用
    val list = ArrayList<String>()
    list.add("Hello")
    list.add("World")

    // Java time APIの使用
    val now = LocalDateTime.now()
    val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
    val formatted = now.format(formatter)

    println("Current time: $formatted")

    // Javaマップの使用
    val map = HashMap<String, Int>()
    map.put("apple", 5)
    map.put("banana", 3)

    // Java 8+ ストリーム
    val total = map.values()
        .stream()
        .mapToInt { it }
        .sum()

    println("Total fruits: $total")
}

生成されるJava:

import java.util.ArrayList;
import java.util.HashMap;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class MainUtils {
    public static void demonstrateJavaInterop() {
        ArrayList<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");

        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formatted = now.format(formatter);

        System.out.println("Current time: " + formatted);

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 5);
        map.put("banana", 3);

        int total = map.values()
            .stream()
            .mapToInt(Integer::intValue)
            .sum();

        System.out.println("Total fruits: " + total);
    }
}

静的メソッドとフィールド

import java.lang.Math
import java.lang.System
import java.util.Collections

fun useStaticMembers() {
    // 静的メソッド
    val sqrt = Math.sqrt(16.0)        // 4.0
    val max = Math.max(10, 20)        // 20

    // 静的フィールド
    val pi = Math.PI                  // 3.141592653589793
    val lineSeparator = System.lineSeparator()

    // 静的ユーティリティメソッド
    val list = mutableListOf(3, 1, 4, 1, 5)
    Collections.sort(list)
    println(list)  // [1, 1, 3, 4, 5]
}

ビルダーパターン

Javaビルダーパターンは自然に動作します:

import java.time.LocalDate
import java.time.format.DateTimeFormatterBuilder
import java.time.temporal.ChronoField

fun useBuilderPattern() {
    val formatter = DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR, 4)
        .appendLiteral('-')
        .appendValue(ChronoField.MONTH_OF_YEAR, 2)
        .appendLiteral('-')
        .appendValue(ChronoField.DAY_OF_MONTH, 2)
        .toFormatter()

    val date = LocalDate.now()
    val formatted = date.format(formatter)
    println(formatted)
}

生成されるJavaコード

クラス生成

jvクラスは慣用的なJavaコードを生成:

// jvクラス
class User(val name: String, var age: Int) {
    fun greet(): String = "Hello, I'm $name"

    fun haveBirthday() {
        age++
    }
}

生成されるJava:

public class User {
    private final String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }

    public String greet() {
        return "Hello, I'm " + name;
    }

    public void haveBirthday() {
        age++;
    }
}

データクラス

// 不変データクラス
data class Point(val x: Double, val y: Double)

// 可変データクラス
data class mutable Counter(var value: Int)

生成されるJava:

// 不変 -> record
public record Point(double x, double y) {}

// 可変 -> 完全クラス
public class Counter {
    private int value;

    public Counter(int value) { this.value = value; }

    public int getValue() { return value; }
    public void setValue(int value) { this.value = value; }

    // equals, hashCode, toString...
}

型マッピング

プリミティブ型

jv型 Java型 注意
Int int 32ビット整数
Long long 64ビット整数
Float float 32ビット浮動小数点
Double double 64ビット浮動小数点
Boolean boolean 真偽値
Char char 16ビット文字
String String 文字列
Unit void 戻り値なし

nullable型

val nullable: String? = null
val nonNull: String = "value"

生成されるJava:

String nullable = null;         // String(nullable)
String nonNull = "value";       // String(non-null、実行時チェック)

コレクション型

jv型 Java型
List<T> List<T>
MutableList<T> List<T>
Set<T> Set<T>
Map<K, V> Map<K, V>
Array<T> T[]

null安全性統合

安全呼び出し演算子

val user: User? = getUser()
val name = user?.name  // 安全なアクセス

生成されるJava:

User user = getUser();
String name = user != null ? user.getName() : null;

エルビス演算子

val name = user?.name ?: "Unknown"

生成されるJava:

String name = user != null ? user.getName() : "Unknown";

null安全なキャスト

val str = obj as? String  // 失敗時はnull

生成されるJava:

String str = obj instanceof String ? (String) obj : null;

コレクションとジェネリクス

型安全性

val list: List<String> = listOf("a", "b", "c")
val map: Map<String, Int> = mapOf("key" to 1)

生成されるJava:

List<String> list = List.of("a", "b", "c");
Map<String, Integer> map = Map.of("key", 1);

ジェネリック関数

fun <T> identity(value: T): T = value
fun <T, R> map(list: List<T>, transform: (T) -> R): List<R> {
    return list.map(transform)
}

生成されるJava:

public static <T> T identity(T value) {
    return value;
}

public static <T, R> List<R> map(List<T> list, Function<T, R> transform) {
    return list.stream().map(transform).collect(Collectors.toList());
}

例外処理

Java例外の処理

fun readFile(path: String): String {
    try {
        return Files.readString(Paths.get(path))
    } catch (e: IOException) {
        println("Error reading file: ${e.message}")
        return ""
    }
}

生成されるJava:

public static String readFile(String path) {
    try {
        return Files.readString(Paths.get(path));
    } catch (IOException e) {
        System.out.println("Error reading file: " + e.getMessage());
        return "";
    }
}

checked例外の処理

jvはchecked例外を自動的に処理:

fun parseUrl(url: String): URL {
    return URL(url)  // MalformedURLExceptionは自動的にthrows句に追加
}

生成されるJava:

public static URL parseUrl(String url) throws MalformedURLException {
    return new URL(url);
}

アノテーション

Javaアノテーションの使用

import javax.annotation.Nullable
import javax.annotation.Nonnull

class UserService {
    @Nullable
    fun findUser(id: String): User? {
        // 実装...
        return null
    }

    @Nonnull
    fun createUser(name: String): User {
        return User(name, 0)
    }
}

生成されるJava:

import javax.annotation.Nullable;
import javax.annotation.Nonnull;

public class UserService {
    @Nullable
    public User findUser(String id) {
        // 実装...
        return null;
    }

    @Nonnull
    public User createUser(String name) {
        return new User(name, 0);
    }
}

ベストプラクティス

1. 慣用的なJavaパターンを使用

// 良い例:Javaの慣用句に従う
fun processItems(items: List<String>): List<String> {
    return items
        .stream()
        .filter { it.isNotEmpty() }
        .map { it.uppercase() }
        .collect(Collectors.toList())
}

2. null安全性を活用

// Javaライブラリを使用する際のnull安全性
fun safeGetProperty(props: Properties, key: String): String? {
    return props.getProperty(key)?.takeIf { it.isNotEmpty() }
}

3. 適切な型を使用

// プリミティブ型を適切に使用
fun calculateSum(numbers: IntArray): Long {
    return numbers.asSequence().map { it.toLong() }.sum()
}

4. 例外を適切に処理

// checked例外を適切に処理
fun parseDate(dateStr: String): LocalDate? {
    return try {
        LocalDate.parse(dateStr)
    } catch (e: DateTimeParseException) {
        null
    }
}

共通パターン

1. ファクトリーパターン

class ConnectionFactory {
    companion object {
        fun createConnection(url: String): Connection {
            return DriverManager.getConnection(url)
        }
    }
}

2. ビルダーパターン

class HttpRequestBuilder {
    private var url: String = ""
    private var method: String = "GET"
    private val headers = mutableMapOf<String, String>()

    fun url(url: String): HttpRequestBuilder {
        this.url = url
        return this
    }

    fun method(method: String): HttpRequestBuilder {
        this.method = method
        return this
    }

    fun header(name: String, value: String): HttpRequestBuilder {
        headers[name] = value
        return this
    }

    fun build(): HttpRequest {
        return HttpRequest.newBuilder()
            .uri(URI.create(url))
            .method(method, HttpRequest.BodyPublishers.noBody())
            .apply {
                headers.forEach { (name, value) ->
                    header(name, value)
                }
            }
            .build()
    }
}

3. コールバックパターン

fun processAsync(callback: (String) -> Unit) {
    CompletableFuture.supplyAsync {
        // 非同期処理
        "Result"
    }.thenAccept(callback)
}

jvとJavaの相互運用性により、既存のJavaエコシステムの豊富なライブラリとツールを活用しながら、より表現力豊かで安全なコードを書くことができます。