본문 바로가기
Programming/Kotlin

Java와 Kotlin 비교 : 변수, null 안정성, 엘비스 연산자, 가변/불변 컬렉션

by Renechoi 2023. 10. 22.

변수 


public class Exam01 {

    public Exam01(){
        String name = "홍길동";

        String format ="사용자의 이름은 : %s";
        String result = String.format(format, name);
        System.out.println(result);

        int age = 10;
        Integer _age = 20;

        double d = 10d;
        Double _d = 20.0;

        float f = 20f;
        Float _f = 20f;

        long l = 10L;
        Long _l = 10L;

    }
}

fun main() {


    // var -> mutable, val -> final(불변)

    // : [타입]
    val name: String = "홍길동"
    var _name: String = "홍길동"
    val n = "홍길동" // <- 타입 추론

    // 코틀린은 primitive 타입이 없고 전부 레퍼런스 타입 -> 모든 것을 객체로 관리한다.
    var i = 10
    var _i: Int = 10

    var d: Double = 20.0


    println("사용자의 이름은: $name")

}

변수 선언

Java

String name = "홍길동";

Kotlin

val name: String = "홍길동"
  • Java에서는 String name = "홍길동";과 같은 방식으로 변수를 선언한다.
  • Kotlin에서는 val name: String = "홍길동"과 같이 선언한다. 여기서 val은 final이라는 것을 의미하며, 이 변수는 불변이다.

자료형

Java

int age = 10;
double d = 10d;

Kotlin

var age: Int = 10
var d: Double = 10.0
  • Java에서는 기본형(primitive types)과 참조형(reference types)이 있다.
  • Kotlin에서는 모든 것이 객체. 따라서, int 대신 Int, double 대신 Double을 사용한다.

출력

Java

System.out.println("사용자의 이름은 : " + name);

Kotlin

println("사용자의 이름은: $name")
  • Java에서는 문자열 연결을 통해 출력을 한다.
  • Kotlin에서는 문자열 템플릿을 사용하여 $변수명 형태로 쉽게 출력할 수 있다.

null 안정성과 엘비스 연산자

이번에는 Java와 Kotlin의 null 안정성과 엘비스 연산자에 대해 알아보자.


public class Exam02 {

    private int a;

    public Exam02(){
        var b = 20; // <- 자바도 타입추론이 가능하다. 대신 자바에는 불변 변수 val은 없음 -> null도 안됨. 반드시 타입이 들어가야함

        int c = 30;

        Integer d = 20;

        Integer e = new Integer(null);

        callFunction(a);
        callFunction(b);
        callFunction(c);
        callFunction(d);
        callFunction(e);  // -> null로 들어오면서 에러 발생
    }

    public void callFunction(Integer i ){
        System.out.println("i = " + i);


        var temp = (i == null) ? "null 입니다" : i;
        System.out.println("temp = " + temp);
    }

}

fun main(){
    val a: Int = 0
    val b = 10
    val c: Int = 20
    val d: Int? = null // 엘비스 연산자 - > 의미는 -> null 값이 들어올 수 있다

    callFunction(a)
    callFunction(b)
    callFunction(c)
    callFunction(d)

    // 자바랑 100% 호환되므로 optional이 가능

    Optional.ofNullable(d).ifPresent() ...



}

fun callFunction(i: Int?){  // i라는 값이 null일 수도 있다
    println(i) // 별도의 null 포인트를 터지지 않고 그냥 찍는다.


    // 코틀린에는 let이라는 함수가 있음. 물음표를 붙이면 i에 대해서 검증을 함
    i?.let{

    }


    // 엘비스 연산자 -> null이 올 수도 있다. -> 이 뒤에 null을 방지할 수 있다. 변수 뒤에다 ?를 붙이면 변수가 null이야?
    // ?. << 변수가 null이 아닐 때
    // ?: << 변수가 null일 때

    i?.let{
        println(it)
    } ?: run {
        println("null 입니다")
    }


    // 자바에서 비슷하게 한다면
    var temp1 = (i == null) ? "null 입니다" : i;
    System.out.println("temp = " + temp1);

    // ->

    val temp2: Serializable = i ?: "null 입니다"
    println("temp = $temp2")

    // 코틀린에서 강한 부분 -> 굉장히 간단
    val temp3 = i?: "null입니다"
    println(temp3)

}


fun callFunction2(i: Int? =100){
    // default로 매개변수에 지정을 해줄 수 있음 -> null이 넘어오거나 값이 안넘어올 수도 있다 

}

Null 안정성

Java

Integer e = new Integer(null);

Kotlin

val d: Int? = null
  • Java에서는 Integer와 같은 객체를 null로 초기화할 수 있다. 하지만 이 경우, 해당 변수를 사용할 때 null 체크를 해야 한다.
  • Kotlin에서는 Int?와 같이 타입 뒤에 ?를 붙여서 null이 될 수 있는 변수임을 명시적으로 표현한다.

엘비스 연산자

Java

var temp = (i == null) ? "null 입니다" : i;

Kotlin

val temp = i ?: "null 입니다"
  • Java에서는 삼항 연산자를 이용해 null 체크를 해야한다.
  • Kotlin에서는 엘비스 연산자 ?:를 사용하여 간단하게 null 체크와 값을 할당할 수 있다.

Optional 클래스와 호환성

Kotlin은 Java와 100% 호환되므로, Java의 Optional 클래스를 사용할 수 있습니다.

Optional.ofNullable(d).ifPresent { ... }

기타 Kotlin null 안정 기능

Kotlin에서는 ?. 연산자와 let 함수, run 함수 등을 활용하여 null 체크를 간편하게 할 수 있다.

i?.let {
    println(it)
} ?: run {
    println("null 입니다")
}

확실히, 엘비스 연산자와 ?., let, run 등을 활용하면 코드가 훨씬 간결하고 안전해진다.

가변, 불변 컬렉션

이번에는 Java와 Kotlin의 컬렉션, 특히 가변과 불변 컬렉션에 대해 비교해보자.



@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
class User {
    private String name;
    private int age;
}

public class Exam03 {

    public Exam03() {
        var userList = new ArrayList<User>();
        userList.add(new User("1", 10));
        userList.add(new User("2", 10));
        userList.add(new User("3", 10));

        var list = Arrays.asList(
            new User("4" , 20),
            new User("5" , 20),
            new User("6" , 20)
        );

        userList.forEach(System.out::println);

        for (int i =0; i< userList.size(); i++){
            var dto = userList.get(i);
            System.out.println("i = " + i);
        }


        // 자바에서도 immutable을 제공 -> but 가변 메서드가 사용되기 때문에 -> 에러 발생 
        var immutable = Collections.unmodifiableCollection(userList);
        immutable.add(new User("5", 60));

    }

}

fun main() {
    // 코틀린에서는 불변과 가변을 중요하게 나눔 
    // 변수에서처럼 컬렉션에서도 -> 

    val userList = mutableListOf<User>()
    userList.add(User("1", 10))
    userList.add(User("2", 10))
    userList.add(User("3", 10))

    // 불변 -> 반드시 초기화때 넣어주어야 함 -> add라는 메서드가 지원을 안함 
    // 자바에서는 불변이어도 add가 보이지만 
    val list = listOf<User>(
        User("4", 40)
    )

    for(element in userList){
        println(element)
    }

    userList.forEach{it->println(it)}
    userList.forEach{ println(it)}

    // index를 보고 싶은 경우에 
    userList.forEachIndexed{index, user -> println("$index, $user") }
    userList.forEachIndexed(fun (index, user){
        println("$index, $user")
    })


    // for문에다가 넣는 방식 
    for ((index, element) in userList.withIndex()){
        println("$index, $element")
    }
}

class User(
    var name: String,
    var age: Int
)

가변 컬렉션

Java

var userList = new ArrayList<User>();
userList.add(new User("1", 10));

Kotlin

val userList = mutableListOf<User>()
userList.add(User("1", 10))
  • Java와 Kotlin 모두 가변 컬렉션을 제공한다.
  • Java에서는 ArrayList를 주로 사용하고, Kotlin에서는 mutableListOf를 사용한다.

불변 컬렉션

Java

var immutable = Collections.unmodifiableCollection(userList);
immutable.add(new User("5", 60)); // 에러 발생

Kotlin

val list = listOf<User>(
    User("4", 40)
)
  • Java에서 불변 컬렉션을 만들기 위해서는 Collections.unmodifiableCollection 메서드를 사용한다. 하지만 이 컬렉션에 add 메서드를 호출하면 런타임에서 에러가 발생한다.
  • Kotlin에서는 listOf를 이용해서 불변 컬렉션을 생성할 수 있다. 불변 컬렉션에서 add 메서드가 제공되지 않으므로, 컴파일 시점에서 에러를 확인할 수 있다.

순회 방법

Java

for (int i = 0; i < userList.size(); i++) {
    var dto = userList.get(i);
    System.out.println("i = " + i);
}

Kotlin

for ((index, element) in userList.withIndex()) {
    println("$index, $element")
}
  • Java에서는 전통적인 for문이나 forEach 메서드를 사용하여 컬렉션을 순회한다.
  • Kotlin에서는 forEach, forEachIndexed, withIndex 등 다양한 방법으로 컬렉션을 순회할 수 있다. -> 인터페이스가 더 많다.

결론

Kotlin에서는 불변성을 중요하게 생각하여, 컬렉션에서도 불변과 가변을 명확히 구분한다. 또한, 컬렉션을 순회하는 방법도 다양하고 직관적이다. 이로 인해 코드가 간결하고 안전하며, 유지보수하기 쉽다.


reference :

반응형