2021-08-22-TIL
2021-08-22-TIL
Kotlin
코틀린에서 빌더패턴이 필요없는 이유
생성자에서 인자의 정보를 적을 수 있기 때문이다.
1
2
3
4
5
val person = Person(
name = "myname",
gender = "male",
age = 10
)
당연히 자바와 같은 표현방식도 가능하다.
1
val person = Person("myname", "male", 10)
- https://www.gunlog.dev/kotlin-None-Builder
자바에서 빌더를 쓰는 이유는 인자가 많은 생성자의 순서를 헷갈리기 쉽고, 선택적인 값마다 생성자를 오버로딩해야 하기 때문이다(2021-04-09 TIL에 정리했다). Kotlin은 언어 차원에서 두 문제를 푼다. 이름 붙인 인자(named argument)를 쓰면 호출부에서 각 값이 어떤 파라미터인지 드러나고 순서도 자유롭다. 기본 인자(default argument)를 쓰면 생략 가능한 값마다 오버로딩을 만들 필요가 없다(Kotlin 문서).
1
2
3
4
5
6
7
class Person(
val name: String,
val gender: String = "unknown",
val age: Int = 0,
)
val person = Person(name = "myname", age = 10) // gender는 기본값
한 가지 제약은 자바에서 Kotlin 생성자를 부를 때다. 문서에 따르면 JVM에서 자바 함수를 호출할 때는 이름 붙인 인자 문법을 쓸 수 없다. 자바 쪽에서는 기본 인자도 그대로 쓸 수 없어서, @JvmOverloads를 붙여 기본값이 있는 파라미터를 하나씩 뺀 오버로딩을 생성해야 한다(Kotlin 문서). 자바와 섞어 쓰는 코드라면 빌더가 여전히 쓸모 있을 수 있다.
유틸리티 클래스, 스태틱 클래스, 컴패니언 클래스
- https://thebook.io/080208/ch02/02/09/
- https://colinch4.github.io/2020-12-01/29_%EC%A0%95%EC%A0%81-%EB%B3%80%EC%88%98%EC%99%80-%EC%BB%B4%ED%8E%98%EB%8B%88%EC%96%B8-%EA%B0%9D%EC%B2%B4/
- https://www.androidhuman.com/2016-07-10-kotlin_companion_object
Kotlin에는 static 키워드가 없다. 자바의 유틸리티 클래스나 정적 멤버는 세 가지로 옮긴다.
- 최상위(top-level) 함수: 클래스 없이 파일에 바로 함수를 선언한다. 상태 없는 유틸리티 함수에 가장 단순한 선택이다.
object선언: 인스턴스가 하나뿐인 싱글턴을 만든다. 처음 접근할 때 스레드 안전하게 초기화된다.companion object: 클래스 안에 두고User.create(...)처럼 클래스 이름으로 멤버를 부른다. 팩터리 메서드나 상수를 둘 때 쓴다.
주의할 점은 컴패니언 객체의 멤버가 정적 멤버가 아니라 런타임에 실제로 존재하는 객체의 인스턴스 멤버라는 것이다. 자바에서 진짜 정적 메서드로 보이게 하려면 @JvmStatic을 붙인다(Kotlin 문서).
인라인 함수
- https://medium.com/mj-studio/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%9E%80-2e455c893c4a
“인라인”이 붙는 기능은 두 가지라서 구분해 둔다. 링크한 글은 인라인 클래스를 다룬다.
인라인 함수는 고차 함수의 비용을 줄이기 위한 것이다. 람다를 인자로 받는 함수는 람다마다 함수 객체를 만들고 클로저를 잡아야 해서 메모리 할당과 가상 호출 비용이 생긴다. inline을 붙이면 컴파일러가 함수 본문과 람다를 호출 지점에 그대로 복사해 넣어 이 비용을 없앤다(Kotlin 문서). 덤으로 람다 안에서 바깥 함수를 빠져나가는 return(non-local return)과, 런타임에 타입 정보를 쓰는 reified 타입 파라미터가 가능해진다.
인라인 클래스(value class)는 값 하나를 감싸는 타입을 비용 없이 만들기 위한 것이다. @JvmInline value class Password(private val s: String)처럼 선언하면 컴파일된 코드에서는 대부분 String으로 다뤄져서 래퍼 객체가 생기지 않는다. 그러면서도 타입 별칭과 달리 String과 섞어 쓸 수 없는 별도 타입이라 잘못된 값을 넘기는 실수를 컴파일 시점에 막는다(Kotlin 문서). 인라인 클래스는 Kotlin 1.5.0에서 value 키워드와 함께 안정화되었다(Kotlin 1.5.0 새 기능).
JPA
OSIV
- https://stylishc.tistory.com/150
OSIV(Open Session In View)는 영속성 컨텍스트를 요청이 끝날 때까지 열어 두는 방식이다. Spring Boot에서는 spring.jpa.open-in-view로 켜고 끄며 기본값은 true다. 이 설정은 OpenEntityManagerInViewInterceptor를 등록해서, 요청을 처리하는 동안 JPA EntityManager를 스레드에 묶어 둔다(Spring Boot 설정 목록).
켜 두면 서비스 계층의 트랜잭션이 끝난 뒤에도 컨트롤러나 뷰에서 지연 로딩이 동작한다. 편하지만, 요청이 끝날 때까지 영속성 컨텍스트와 함께 DB 커넥션도 오래 붙잡게 되어 트래픽이 많을 때 커넥션 풀에 부담이 된다. 또 컨트롤러에서 엔티티를 건드리면 어디서 쿼리가 나가는지 추적하기 어려워진다. 끄면 트랜잭션 밖에서 지연 로딩을 할 때 LazyInitializationException이 나므로, 필요한 데이터를 서비스 계층에서 미리 조회해 DTO로 넘기는 구조가 강제된다.
댓글
아직 댓글이 없습니다