자바 언어 스터디를 진행 중인데 요새 핫한 코틀린이라는 언어가 자바와 무슨 차이가 있는지, 그 장점이 뭐길래 이렇게 핫한(?) 건지에 대해 궁금함이 생겨 찾아보게 되었습니다.
Kotlin이란?
Java 가상 머신에서 동작하는 프로그래밍 언어로,
- Java와의 상호운용성
- Kotlin은 Java와 100% 상호운용성을 가지고 있기 때문에 Java 라이브러리와 API를 쉽게 사용 가능
- 또한, Java로 작성된 코드도 Kotlin에서 쉽게 사용할 수 있습니다.
- 상호운용성이란
- 하나의 시스템이 동일 또는 이기종의 다른 시스템과 아무런 제약이 없이 서로 호환되어 사용할 수 있는 성질
- 널 안전성
- Kotlin은 널 안전성을 지원하는 언어로,
- null 값으로 인한 오류를 방지하고 안전하게 코드를 작성할 수 있도록 도와줌
- 기타 특징
확장 함수 Kotlin은 확장 함수(Extension Function)를 지원하는데, 이는 기존 클래스에 새로운 메소드를 추가할 수 있게 해줍니다. 이는 코드의 가독성을 높이고, 새로운 기능을 추가할 때 유용합니다.람다식 Kotlin은 람다식을 지원하는데, 이는 함수를 변수처럼 사용할 수 있도록 해줍니다. 람다식을 사용하면 코드를 간결하게 작성할 수 있고, 함수형 프로그래밍을 적용할 수 있습니다.데이터 클래스 Kotlin은 데이터 클래스(Data Class)를 지원하는데, 이는 데이터를 표현하는 데 유용합니다. 데이터 클래스를 사용하면 간결하고 가독성이 높은 코드를 작성할 수 있습니다.코루틴 Kotlin은 코루틴(Coroutine)을 지원하는데, 이는 비동기 프로그래밍을 쉽게 작성할 수 있도록 해줍니다. 코루틴을 사용하면 복잡한 비동기 코드를 간단하게 작성할 수 있고, 동시성 처리도 쉽게 구현할 수 있습니다.
널이 될 수 있는 타입과 널이 될 수 없는 타입
(Nullable types and Non-Null Types)
코틀린의 타입(type) 시스템은 null 참조 코드의 위험성을 없애기 위한 것
→ null 참조 코드는 **Billion Dollar Mistake라고도 알려짐
- 왜 넣었을까?
- 만든 아저씨 왈 : 그렇게 하는 게 훨씬 쉬웠다
Java를 포함한 많은 프로그래밍 언어에서 가장 일반적인 함정 중 하나
- null 참조의 멤버에 접근하면 null 참조 예외(null reference exception)가 발생함
- 코틀린의 타입(type) 시스템은 코드에서 NullPointerExeption을 제거하기 위한 것
NPE의 원인
- throw NullPointerException을 명시적으로 호출하는 것
- 초기화와 관련하여 아래와 같은 특성으로 데이터의 불일치가 발생할 때
- 생성자에서 this를 초기화하지 않고도 사용할 수 있으며, 다른 곳으로 전달되어 사용할 수 있음
- Java interoperation:
- **플랫폼 유형**의 null 참조에서 멤버에 접근하려고 시도함
Generic types used for Java interoperation with incorrect nullability, e.g. a piece of Java code might add null into a Kotlin MutableList, meaning that MutableList<String?> should be used for working with it;
- 외부의 자바 코드로 인한 기타 문제들
그렇다면 null은 왜 문제가 되는가?
- null을 사용하면 변수나 객체의 상태를 추적하는 것이 어렵고,
- null 포인터 예외(null pointer exception)과 같은 예기치 않은 오류가 발생 가능
- null을 사용하면 변수나 객체의 상태를 추적하는 것이 어렵다는 말은 무슨 의미일까?
- 예를 들어, 다음과 같은 User 클래스가 있다고 가정
- ⬇️ User 객체를 생성하고, 해당 객체의 이름을 출력하는 코드
public class User {
private String name; public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
} //User 객체는 이름을 가지고 있으며, getName() 메소드를 통해 이름을 반환
-
- 이때 user 변수가 null을 가지고 있다면 getName() 메소드를 호출할 수 없기 때문에 NullPointerException이 발생
- 따라서 null을 사용하는 경우에는 예외 처리를 추가하여 해당 상황을 처리해야 함
위 코드에서는 user 변수가 null인 경우에 "User is null" 메시지를 출력하도록 처리User user = null; if (user != null) { System.out.println(user.getName()); } else { System.out.println("User is null"); }
- 이때 user 변수가 null을 가지고 있다면 getName() 메소드를 호출할 수 없기 때문에 NullPointerException이 발생
- 이처럼 null을 처리하는 방법은 상황에 따라 다양하게 다르기 때문에, null을 사용하면 변수나 객체의 상태를 추적하기 어려워지게 되는 것!!!
- 그 이유는 null이 발생할 수 있는 경우를 모두 예측하여 처리해야 하기 때문임!!!
Java와 비교하여 Kotlin의 널 안정성
1. 명시적인 Nullable 타입:
Kotlin에서는 타입 뒤에 물음표(?)를 붙여 Nullable 타입을 명시적으로 선언
- 이를 통해 해당 변수가 null 값을 가질 수 있음을 명확히 표시 가능
- 반면, Java에서는 기본적으로 모든 참조 타입이 null 값을 가질 수 있기 때문에,
- 어떤 변수가 null 값을 가질지 명확히 알기 힘듬
Kotlin
val nullableString : String? = null
Java
String nullableString = null;
위의 그렇다면 null은 왜 문제가 되는가?에 대한 코틀린 코드
코틀린에서는 null 안정성(null safety)을 지원하여, null로 인한 예외 처리를 최소화
⬇️ 따라서, 위의 User 클래스의 null 문제를 해결하기 위한 코틀린 코드
data class User(val name: String)
- 위 코드에서는 User 클래스를 선언하고, 생성자에서 name 변수를 선언
- 코틀린에서는 변수를 선언할 때 자동으로 null 안정성을 지원하기 때문에,
- name 변수가 null을 가질 수 없음!!!!!!!!!!!!!!!
- 따라서, 아래와 같이 User 객체를 생성하고, 해당 객체의 이름을 출력하는 코드를 작성하면
- null로 인한 예외 처리를 하지 않아되는 것!!!!!!!
val user = User("John")
println(user.name)
// user 변수에 User 객체를 생성하고, 해당 객체의 name 변수를 출력하는 코드
이때 user 변수가 null을 가지고 있다면 컴파일 오류가 발생하기 때문에, NullPointerException과 같은 예외 처리를 하지 않아도 되는 것!!!!
2. 안전한 호출(Safe Call Operator)
Kotlin은 안전한 **호출 연산자 ?.**를 사용하여 null 검사와 메서드 호출을 동시에 수행
- null 포인터 예외(NullPointerException)를 방지
- 반면, Java에서는 명시적으로 null 검사를 수행하고 메서드를 호출해야 함
Kotlin
val length = nullableString?.length
Java
int length = (nullableString != null) ? nullableString.length() : null;
3. 엘비스 연산자(Elvis Operator):
- Kotlin에서는 엘비스 연산자 **?:**를 사용하여 null 값일 경우 기본 값을 제공 가능
- Java에서는 삼항 연산자를 사용해야 함
Kotlin
val safeLength = nullableString?.length ?: 0
Java
int safeLength = (nullableString != null) ? nullableString.length() : 0;
4. 강제 not-null(Non-null Assertion Operator)
- Kotlin에서는 not-null 단언 연산자 **!!**를 사용하여 강제로 null이 아님을 보장
- 이 경우, 값이 null이면 NullPointerException이 발생
- Java에서는 not-null 검사 없이 직접 호출하면, 값이 null일 때 NullPointerException이 발생
Kotlin
val nonNullString: String = nullableString!! // Kotlin
Java
String nonNullString = nullableString;// Java
// 값이 null일 때 NullPointerException 발생 가능