Java와 Kotlin 비교: default value, when, 확장함수
Kotlin의 default value 사용하기
public class Exam08 {
public static void main(String[] args) {
var registerDto = new Store();
new Exam08(registerDto);
}
public Exam08(Store store){
// null point -> 터짐
var stringRegisteredAt = toLocalDateTimeString(store.getRegisteredAt());
}
public String toLocalDateTimeString(LocalDateTime localDateTime){
// null을 방지하려고 이런식으로 방어 로직을 짬
LocalDateTime temp;
if(localDateTime == null){
temp = localDateTime.now();
}
// 혹은 optional로 받아서 orElseGet으로
return localDateTime.format(DateTimeFormatter.ofPattern("yyyy MM dd"));
}
}
@Data
class Store {
private LocalDateTime registeredAt;
}
// 이러한 null 체크 로직, optional을 코틀린에서 더 쉽게 처리할 수 있다면 ?
fun main() {
Exam08(Store())
}
data class Store(
// data 클래스를 만들 때부터 null일 수 있음을 명시해줌
var registeredAt: LocalDateTime ?= null
)
class Exam08{
constructor(store: Store){
}
// 메서드에서 반환 -> 콜론으로 -> 뭘 리턴하는지는 마지막에 표현함
fun toLocalDateTimeString(localDateTime: LocalDateTime?):String{
// 이것만으로 변수 세팅이 됨
// var temp = localDateTime ?: LocalDateTime.now()
// ?을 작성하면 ->
// return localDateTime?.format(DateTimeFormatter.ofPattern("yyyy MM dd"))
// 합치면 ->
return (localDateTime ?: LocalDateTime.now()).format(DateTimeFormatter.ofPattern("yyyy MM dd"))
}
}
Kotlin에서의 Null Safety
Kotlin은 널 안정성(Null Safety)을 명시적으로 다루어, 자바에서 발생하는 Null Pointer Exception을 피할 수 있는 여러 방법을 제공한다.
기본값(Default Value)
Kotlin에서는 함수나 클래스의 파라미터에 기본값을 설정할 수 있다. 이를 통해 널 값을 피하거나 대체할 수 있다.
data class Store(
var registeredAt: LocalDateTime ?= null
)
Store
클래스의 registeredAt
프로퍼티에 기본값으로 null
을 설정했다. 이렇게 하면 Store
객체를 생성할 때 registeredAt
을 명시적으로 설정하지 않아도 된다.
Elvis 연산자(?:
)
Kotlin에서는 ?:
연산자를 사용하여 널 체크를 더 간결하게 할 수 있다.
var temp = localDateTime ?: LocalDateTime.now()
위 코드에서 localDateTime
이 null
이라면 LocalDateTime.now()
가 temp
에 할당된다.
메서드 예제
fun toLocalDateTimeString(localDateTime: LocalDateTime?):String {
return (localDateTime ?: LocalDateTime.now()).format(DateTimeFormatter.ofPattern("yyyy MM dd"))
}
Java와 Kotlin의 차이점
- Java에서는 Null 체크를 위해 명시적인 조건문이나
Optional
을 사용해야 한다. - Kotlin에서는 Elvis 연산자, 기본값 설정 등을 통해 더 간결하고 안전한 코드를 작성할 수 있다.
when
Kotlin의 when
표현식은 Java의 switch
문과 if-else
조건문을 대체할 수 있는 문법이다. 코드를 더 간결하고 읽기 쉽게 만들 수 있게 도와준다.
public class Exam09 {
public static void main(String[] args) {
}
public Exam09(StoreUser storeUser){
// service logic
if (storeUser.getRole().equals("MASTER")){
} else if (storeUser.getRole().equals("ADMIN")) {
} else if (storeUser.getRole().equals("USER")){
}
switch (storeUser.getRole()){
case "MASTER":
break;
case "ADMIN":
break;
case "USER":
break;
default:
// 로직
}
try {
} catch (Exception e){
if (e instanceof NullPointerException){
}
}
}
}
@Data
class StoreUser{
private String name;
private String role;
}
// java에서 이와 같이 분기문을 처리하는 방식 -> 코틀린에서는 ?
fun main(){
when(""){
""-> {
}
"MASTER" ->{
}
}
var result = when(""){
"MASTER" -> {
"master"
}
else -> {
"default"
}
}
var any : Any = "";
// instanceof 와 동일
when (any) {
is String ->{}
is Int ->{}
is Boolean ->{}
}
// switch 문과 매우 동일하게 생겼지만 break을 안해도 된다.
var exception = RuntimeException()
when(exception) {
is NullPointerException ->{}
}
// 표현식을 담을 수도 있다.
var number = 10
when (val n = number % 2){
0 -> {println(n)}
else -> { println(n)}
}
}
기본 사용법
Java에서의 분기문
Java에서는 switch
문과 if-else
로 분기 처리를 한다.
if (storeUser.getRole().equals("MASTER")) {
// MASTER 로직
} else if (storeUser.getRole().equals("ADMIN")) {
// ADMIN 로직
} else if (storeUser.getRole().equals("USER")) {
// USER 로직
}
Kotlin에서의 when
Kotlin에서는 when
을 사용하여 이를 훨씬 간결하게 표현할 수 있다.
when(storeUser.role) {
"MASTER" -> {
// MASTER 로직
}
"ADMIN" -> {
// ADMIN 로직
}
"USER" -> {
// USER 로직
}
else -> {
// 기타 로직
}
}
when
의 다양한 사용법
결과 값을 변수에 할당
when
표현식의 결과 값을 변수에 할당할 수 있다.
val result = when(storeUser.role) {
"MASTER" -> "master"
else -> "default"
}
Type Check
Kotlin에서 when
은 instanceof
와 같은 역할도 할 수 있다.
when(any) {
is String -> {}
is Int -> {}
is Boolean -> {}
}
표현식 사용
Kotlin에서는 when
내부에서도 표현식을 사용할 수 있다.
when (val n = number % 2) {
0 -> { println(n) }
else -> { println(n) }
}
장점과 특징
break
문이 필요 없다. 각 분기마다 자동으로break
가 적용된다.- 다양한 표현식과 함께 사용할 수 있어 유연하다.
- 코드가 간결해져 가독성이 향상된다.
확장 함수
코틀린에서는 확장 함수(extension function)라는 강력한 기능을 제공한다. 이를 통해 이미 존재하는 클래스에 새로운 함수를 추가할 수 있다. Java에서 복잡하게 작성해야 했던 코드를 코틀린에서는 매우 간결하게 만들 수 있다.
public class Exam10 {
public Exam10(ExamUser examUser){
if (examUser!=null && examUser.getName() != null){
if (!examUser.getName().isBlank()){
// 로직
}
}
// 혹은
var optionalUser = Optional.ofNullable(examUser);
optionalUser.ifPresent(it ->{
Optional.ofNullable(examUser.getName()).ifPresent(name->{
if(!name.isBlank()){
// 로직
}
});
});
// 이러한 방어 코드를 작성하게 됨
}
public static void main(String[] args) {
new Exam10(new ExamUser());
new Exam10(new ExamUser("aa"));
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class ExamUser{
private String name;
}
// notblank를 사용하려고 이렇게 util 함수를 만들기도 한다.
class StringUtils{
public static boolean notBlank(String value){
return !value.isBlank();
}
}
class ObjectUtils{
public static boolean isNotNull(Object object){
return object != null;
}
}
// 이러한 코드를 코틀린에서는 ?
fun main(){
val user = ExamUser(name = "abcd");
exam10(user)
}
fun exam10(examUser: ExamUser?){
examUser?.let {
it.name?.let{name ->
println(name)
}
}
examUser?.let{
if(it.name.isNullOrEmpty()){
// 로직
}
// 뒤에 만든 함수를 마치 스트링 클래스에 생긴 메서드처럼 동작을 함 -> 내가 원하는 특정 클래스를 이미 존재하는 클래스에 추가가 가능함
if(it.name.isNotNullOrBlank()){
}
if (examUser.isNotNull() && examUser.name.isNotNullOrBlank()){
// 로직
}
}
}
data class ExamUser(
var name: String ?=null
)
// 코틀린의 확장 함수 -> extension function
fun String.isNotNullOrBlank(): Boolean{
return !this.isNotNullOrBlank();
}
// 코틀린에서 모든 Object의 조상은 Any
fun Any?.isNotNull():Boolean{
return this!=null;
}
// 중요한 점은 확장 함수 -> 자주 사용하는 함수들을 만들 수도 있고 이미 만들어진 것을 정의할 수 있음
Java에서의 방어 코드
Java에서는 객체나 필드의 Null 여부를 체크하는 방어 코드를 작성해야 한다.
if (examUser!=null && examUser.getName() != null){
if (!examUser.getName().isBlank()){
// 로직
}
}
Util 함수를 이용한 방법
Java에서는 별도의 유틸리티 클래스를 만들어 이러한 로직을 재사용할 수 있게 한다.
public static boolean notBlank(String value){
return !value.isBlank();
}
Kotlin에서의 확장 함수
하지만 코틀린에서는 확장 함수를 사용해 이러한 로직을 더 간결하고 직관적으로 만들 수 있다.
fun String.isNotNullOrBlank(): Boolean{
return !this.isNotNullOrBlank();
}
Null 체크 간소화
fun Any?.isNotNull():Boolean{
return this!=null;
}
확장 함수를 이용한 코드
이러한 확장 함수를 이용하면, 코드를 다음과 같이 간결하게 작성할 수 있다.
if (examUser.isNotNull() && examUser.name.isNotNullOrBlank()){
// 로직
}
장점
- 기존 클래스를 수정하지 않고도 새로운 기능을 추가할 수 있다.
- 코드가 간결해져 가독성이 향상된다.
- 확장 함수를 재사용하여 코드 중복을 줄일 수 있다.
reference:
- fastcampus 시그니처 백엔드 path 초격차 패키지 course 5
- https://kotlinlang.org/spec/introduction.html#reference