Java to Kotlin: 코드 변환
Java to Kotlin: 코드 변환
1. IntelliJ IDEA의 자동 변환 기능 활용
사용 방법:
- 변환하고 싶은 Java 파일(
.java)을 엽니다. - Code 메뉴 -> Convert Java File to Kotlin File을 선택합니다.
- 단축키:
Ctrl + Alt + Shift + K(Windows/Linux),Cmd + Alt + Shift + K(macOS)
- 단축키:
- IntelliJ IDEA가 자동으로 Kotlin 코드로 변환해 줍니다. 필요한 경우, 변환된 코드에 대한 개선 사항을 제안하기도 합니다.
예시:
Java 코드 (User.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
자동 변환된 Kotlin 코드 (User.kt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.example // 필요시 패키지 추가
class User(var name: String?, var age: Int) {
// equals, hashCode, toString은 data class가 아닐 경우 IntelliJ가 직접 생성해줌
// 하지만 대부분의 경우 data class로 변환하는 것이 더 Kotlin스럽다.
// 아래 2번에서 data class로 변환하는 방법을 설명합니다.
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as User
if (name != other.name) return false
if (age != other.age) return false
return true
}
override fun hashCode(): Int {
var result = name?.hashCode() ?: 0
result = 31 * result + age
return result
}
override fun toString(): String {
return "User(name=$name, age=$age)"
}
}
` `
2. Kotlin스럽게 코드 다듬기 (Idiomatic Kotlin)
2.1. Data Class 활용
Java의 POJO(Plain Old Java Object)는 Kotlin의 data class로 완벽하게 대체될 수 있습니다. equals(), hashCode(), toString(), copy() 등을 자동으로 생성해 줍니다.
Kotlin 코드 (개선된 User.kt)
1
data class User(var name: String, var age: Int)
팁: var 대신 val을 사용하여 불변(immutable) 객체로 만드는 것이 권장됩니다. 가능한 한 val을 우선적으로 사용하고, 변경이 필요한 경우에만 var을 사용하세요.
1
data class User(val name: String, val age: Int)
2.2. Null Safety 적용
Kotlin은 NullPointerException(NPE)을 방지하기 위한 강력한 Null Safety 기능을 제공합니다. 자동 변환 시 String?와 같이 nullable 타입으로 변환될 수 있습니다.
?(Nullable Type): 해당 변수가null값을 가질 수 있음을 명시합니다.!!(Non-null Assertion Operator): 개발자가null이 아님을 확신할 때 사용하지만,null인 경우 NPE를 발생시키므로 사용을 지양하는 것이 좋습니다.?.(Safe Call Operator):null이 아니면 호출하고,null이면null을 반환합니다.?:(Elvis Operator):null일 경우 기본값을 제공합니다.
Java 코드:
1
2
3
4
5
6
7
public String getDisplayName(String firstName, String lastName) {
if (lastName != null && !lastName.isEmpty()) {
return firstName + " " + lastName;
} else {
return firstName;
}
}
Kotlin 코드 (변환 후 개선):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun getDisplayName(firstName: String, lastName: String?): String { // lastName을 nullable로 선언
return if (!lastName.isNullOrEmpty()) { // isNullOrEmpty()는 null과 빈 문자열 모두 처리
"$firstName $lastName" // String Interpolation
} else {
firstName
}
}
// 또는 Elvis Operator 활용
fun getDisplayNameElvis(firstName: String, lastName: String?): String {
return firstName + (lastName?.let { " $it" } ?: "")
// lastName이 null이 아니면 " $lastName"을 반환, null이면 ""을 반환
}
// 더 간결하게
fun getDisplayNameConcise(firstName: String, lastName: String?): String =
firstName + (lastName?.takeIf { it.isNotEmpty() }?.let { " $it" } ?: "")
2.3. 람다(Lambda) 및 고차 함수(Higher-Order Functions) 활용
Java 코드:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class CollectionExample {
public static List<String> filterAndMap(List<String> names) {
List<String> result = new ArrayList<>();
for (String name : names) {
if (name.startsWith("A")) {
result.add(name.toUpperCase());
}
}
return result;
}
// Java 8 Stream API 사용 시
public static List<String> filterAndMapStream(List<String> names) {
return names.stream()
.filter(name -> name.startsWith("A"))
.map(String::toUpperCase)
.collect(Collectors.toList());
}
}
Kotlin 코드:
1
2
3
4
5
fun filterAndMap(names: List<String>): List<String> {
return names
.filter { it.startsWith("A") } // 람다를 사용하여 필터링
.map { it.uppercase() } // 람다를 사용하여 매핑
}
2.4. 확장 함수(Extension Functions) 활용
Java 코드:
1
2
3
4
5
6
7
8
9
10
11
public class StringUtil {
public static String capitalizeFirstLetter(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
// 사용 예시:
// StringUtil.capitalizeFirstLetter("hello");
Kotlin 코드:
1
2
3
4
5
6
7
8
9
10
fun String.capitalizeFirstLetter(): String { // String 클래스에 확장 함수 추가
return if (isNullOrEmpty()) {
this
} else {
this.substring(0, 1).uppercase() + this.substring(1)
}
}
// 사용 예시:
// "hello".capitalizeFirstLetter()
2.5. 싱글톤(Singleton) 객체
Java 코드:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MySingleton {
private static MySingleton instance = new MySingleton();
private MySingleton() {}
public static MySingleton getInstance() {
return instance;
}
public void doSomething() {
System.out.println("Doing something...");
}
}
Kotlin 코드:
1
2
3
4
5
6
7
8
object MySingleton {
fun doSomething() {
println("Doing something...")
}
}
// 사용 예시:
// MySingleton.doSomething()
2.6. 프로퍼티(Properties) 활용
Java의 getter/setter는 Kotlin의 프로퍼티로 대체되어 더욱 간결해집니다.
Java 코드:
1
2
3
4
5
6
7
8
9
10
11
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Kotlin 코드:
1
2
3
4
5
6
class Person {
var name: String = "" // getter, setter가 자동으로 생성됨
}
// 또는 주 생성자에서 선언
// class Person(var name: String)
3. Java-Kotlin 상호 운용성 고려하기
- Kotlin에서 Java 호출: Kotlin 코드는 Java 클래스, 메서드, 필드를 자연스럽게 호출할 수 있습니다. Java의 원시 타입은 Kotlin의 내장 타입으로 매핑됩니다.
- Java에서 Kotlin 호출:
- 패키지 레벨 함수 (
Top-level functions): Kotlin 파일의 최상위에 선언된 함수는 Java에서FileNameKt.functionName()형태로 호출할 수 있습니다. (예:MyFileKt.myFunction()) @JvmStatic: Kotlinobject나companion object내의 함수/프로퍼티를 Java에서 정적(static) 멤버처럼 접근하게 해줍니다.@JvmField: Kotlin 프로퍼티를 Java에서 필드처럼 직접 접근하게 해줍니다.@JvmOverloads: 기본 파라미터를 가진 Kotlin 함수에 대해 Java에서 오버로드된 메서드를 자동으로 생성해줍니다.@JvmName: Java에서 Kotlin 함수나 프로퍼티가 다른 이름을 가지도록 지정합니다.
- 패키지 레벨 함수 (
- SAM (Single Abstract Method) 변환: Kotlin은 Java 인터페이스의 단일 추상 메서드에 대해 람다를 사용하여 더 간결하게 인스턴스를 생성할 수 있습니다.
예시: @JvmStatic과 @JvmOverloads
Kotlin 코드:
1
2
3
4
5
6
7
8
9
class Greeter {
companion object {
@JvmStatic
@JvmOverloads
fun greet(name: String, prefix: String = "Hello"): String {
return "$prefix, $name!"
}
}
}
Java 코드에서 호출:
1
2
3
4
5
6
7
8
9
10
public class JavaCaller {
public static void main(String[] args) {
// @JvmStatic 덕분에 Greeter.Companion이 아닌 Greeter에서 직접 호출 가능
String greeting1 = Greeter.greet("Kotlin User"); // prefix 기본값 사용
String greeting2 = Greeter.greet("Java User", "Hi"); // prefix 지정
System.out.println(greeting1); // Output: Hello, Kotlin User!
System.out.println(greeting2); // Output: Hi, Java User!
}
}
4. 컨버팅 시 주의사항 및 팁
- Nullability 명시: 자동 변환된 코드의
String?나Int?등을 보고, 실제로null이 될 수 있는지 없는지 신중하게 판단하여 타입을 확정하세요.lateinit이나by lazy를 적절히 활용하는 것도 좋습니다. - 상수(Constants): Java의
public static final상수는 Kotlin에서const val또는companion object내의val로 대체됩니다.1 2
// Java: public static final String MY_CONSTANT = "value"; // Kotlin: const val MY_CONSTANT = "value" // 최상위 또는 object 내에서
- 예외 처리: Kotlin은
checked exception과unchecked exception을 구분하지 않지만, Java 라이브러리를 사용할 때는 여전히try-catch블록으로 예외를 처리해야 할 수 있습니다.runCatching과 같은 Kotlin의 함수형 예외 처리도 고려해 보세요. - 빌더 패턴: Java에서 많이 사용되는 빌더 패턴은 Kotlin의 명명된 인자(Named Arguments)와 기본 인자(Default Arguments)를 활용하면 더 간결하게 만들 수 있습니다. 또는
apply스코프 함수를 사용하여 빌더와 유사한 문법을 구현할 수도 있습니다. - 제네릭(Generics): Java의 와일드카드(
? extends,? super)는 Kotlin의out(공변성, covariant)과in(반공변성, contravariant) 키워드로 대체됩니다. - 코드 스타일: Kotlin은 Java와 다른 코드 컨벤션을 가집니다. IntelliJ IDEA의 코드 포맷팅 (
Ctrl + Alt + L또는Cmd + Alt + L)을 사용하여 Kotlin 스타일에 맞게 정리하는 습관을 들이세요.
This post is licensed under CC BY 4.0 by the author.