인프런 커뮤니티 질문&답변

아무거나123님의 프로필 이미지

작성한 질문수

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)

2강. 코틀린에서 null을 다루는 방법

코틀린으로 한번 래핑 (수정)

작성

·

674

7

코틀린에서 자바코드를 사용할 때 플랫폼 타입 사용에 유의하여야한다고 하셨습니다.

팁으로 자바 코드를 널 가능성을 확인하는 코드를 삽입하던지 아니면 코틀린으로 한번 래핑하라고 하셨는데 여기서 코틀린으로 한번 래핑하라는게 무슨 의미인지 잘 모르겠습니다

4강입니다

 

답변 2

13

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요! 아무거나123님~~~ 정말 좋은 질문 이십니다~~ 😊😊 휴일에도 공부하시고 크으~ 대단하십니다!!! 바로 한 번 답변 드려보도록 할게요!!

 

다음과 같은 Java 코드가 있습니다!

public class JavaContext {

  public String getValue(String key) {
    if ("A".equals(key) || "B".equals(key)) {
      return "OK";
    }
    return null;
  }

}

key에 어떤 값이 들어오는지에 따라 null이 아닌 문자열을 반환하기도, null인 문자열을 반환하기도 합니다!

 

이 JavaContext의 getValue 함수를 코틀린에서 사용한다고 해볼게요!!!

그런데 우리의 프로젝트는 정말정말 size가 커서 JavaContext를 많이많이 사용해야 합니다! 자 우선 간단히 3군데의 Kotlin 코드에서 JavaContext의 getValue 함수를 가져다 사용한다고 해볼게요!!

class A(private val javaContext: JavaContext) {
  fun logic1() {
    val str: String = javaContext.getValue("A")
    // ... 생략
  }
}

class B(private val javaContext: JavaContext) {
  // logic2, 위와 비슷하다.
}

class C(private val javaContext : JavaContext) {
  // logic3, 위와 비슷하다.
}

대략 이런 느낌일겁니다! 자 이 코드의 문제가 무엇일까요?!

 

정답은, JavaContext의 의존성이 지나치게 퍼져 있다는 것입니다. 바꿔 말하면, JavaContext를 사용하는 클래스가 너무 많아요! JavaContext는 Java 라이브러리이고, 지금은 A나 B일 때 non-null String을 반환하지만, 버전이 변경되면서 또 어떻게 될지는 모르죠! 즉, JavaContext 라는 클래스 변경에 우리의 프로젝트는 매우 취약한 상태입니다.

그림으로 나타내면 다음과 같죠!

image

그림에서와 같이, JavaContext에 변경이 일어날 경우, A / B / C 클래스 모두 수정을 해야 하고, 만약 사용하는 사용처가 늘어날수록 영향범위는 커져서 NPE와 같이 예상치 못한 이슈가 뻥뻥 터질 수 있습니다!

 

그래서 우리는 wrapping을 해야 합니다!! wrapping이란 대상 클래스를 한 번더 감싸는 건데요! 코드로 한 번 보여드릴게요!

JavaContext라는 클래스를 Kotlin 코드로 감싸겠습니다. 그리고 여기서 우리가 원하는대로 안전하게 null 여부를 제어할 수 있죠. 예를 들면 null인 경우 예외를 낼 수도 있을겁니다.

class JavaContextWrapper(private val javaContext: JavaContext) {
  fun getValue(key: String): String {
    return javaContext.getValue(key)
      ?: throw IllegalArgumentException("key=${key}는 null을 반환했습니다.")
  }
}

네, 이제 JavaContextWrapper에서는 확실한 String을 줍니다!! (구현에 따라서는 String?을 줄 수도 있겠죠!!)

그럼 이제 A / B / C Class에서는 JavaContext를 직접 사용하지 않고, JavaContextWrapper를 사용합니다! 하나만 예를 들어볼게요!

class A(private val wrapper: JavaContextWrapper) {
  fun logic1() {
    val str = wrapper.getValue("A") // 확실한 String 타입
    // ... 생략
  }
}

 

전체적인 구조 역시 바뀝니다.

image이렇게 되면, JavaContext라는 외부 라이브러리가 어떻게 바뀌건, A / B / C 클래스는 아무런 걱정없이 JavaContext의 기능을 사용할 수 있고요! JavaContext의 null 관련 정책이 변경되더라도 JavaContextWrapper만 수정하면 되기 때문에 무척 편하죠~ 😊

 

그래서 결국 wrapping을 한다라는 의미는 Java의 플랫폼 타입과 직접적으로 맞닿는 우리의 Kotlin 코드를 최소한으로 하여, 영향범위를 최소화하고, 예상치 못한 일이 발생했을 때 대응해야 하는 cost를 최소로 한다 라는 의미입니다!!

 

제 답변이 도움이 되었다면 좋겠네요~!! 혹시라도 더 궁금하신 내용 있으시면 편하게 질문 부탁드리겠습니다!

감사합니다!! 🙏🙏

 

와... 정말 열정적으로 알려주시는 모습에 감동했습니다 ㅠㅠ ...

코틀린을 애매하게 아는 상태인데, 수강할 지 고민 중이었는데.. 수강하러 갑니다 ㅎㅎ

1

설명을 너무 친절하고 자세히 알려주셔서 엄청 잘 이해되었습니다.

정말 감사합니다 ! ^^