Java相互運用性¶
English | 日本語
このガイドでは、jvがJavaコード、ライブラリ、そしてより広いJavaエコシステムとどのように相互運用するかを説明します。
目次¶
概要¶
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型¶
生成されるJava:
コレクション型¶
| jv型 | Java型 |
|---|---|
List<T> |
List<T> |
MutableList<T> |
List<T> |
Set<T> |
Set<T> |
Map<K, V> |
Map<K, V> |
Array<T> |
T[] |
null安全性統合¶
安全呼び出し演算子¶
生成されるJava:
エルビス演算子¶
生成されるJava:
null安全なキャスト¶
生成されるJava:
コレクションとジェネリクス¶
型安全性¶
生成されるJava:
ジェネリック関数¶
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例外を自動的に処理:
生成されるJava:
アノテーション¶
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エコシステムの豊富なライブラリとツールを活用しながら、より表現力豊かで安全なコードを書くことができます。