클래스

다음 내용을 정리한다.

  • 클래스 계층을 정의하는 방식
  • 상속 제어 변경자
  • 가시성 변경자
  • sealed 변경자

인터페이스

간단한 인터페이스를 정의해보자.

1
2
3
interface Clickable {
fun click()
}

위 간단한 인터페이스를 구현해보자.

1
2
3
class Button : Clickable {
override fun click() = println("Button was clicked")
}

extends 와 implements 키워드를 사용하는 Java 와 다르다.
클래스 이름 뒤에 콜론을 붙여서 클래스 확장과 인터페이스 구현을 모두 처리한다.

인터페이스 메서드도 디폴트 구현을 제공할 수 있다.
자바처럼 default 키워드를 붙일 필요는 없다.

1
2
3
4
interface Clickable {
fun click()
fun showOff() = println("I am clickable") // 디폴트 구현이 있는 메서드
}
Read more

함수 정의와 호출

다음 내용들을 정리한다.

  • 코틀린의 컬렉션
  • 함수 정의와 호출
  • 확장 함수와 확장 프로퍼티
  • 컬렉션 처리: 가변 길이 인자, 중위 함수 호출, 구조 분해 선언
  • 로컬 함수

컬렉션

코틀린에서의 자체 컬렉션 기능은 없다.
자바의 컬렉션을 사용한다.

1
2
3
4
5
6
7
val set = hashSetOf(1, 2, 3)
val list = arrayListOf(1, 2, 3)
val map = hashMapOf(1 to "one", 2 to "two", 3 to "three ")

println(set.javaClass) // java 의 getClass() 와 동일
println(list.javaClass)
println(map.javaClass)

출력 결과는 다음과 같다.

1
2
3
class java.util.HashSet
class java.util.ArrayList
class java.util.HashMap

함수 구현

collection 의 원소에 prefix, postfix 를 붙이고 separator 로 구분짓는 메서드를 만들자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fun <T> joinToString(
collection: Collection<T>,
separator: String,
prefix: String,
postfix: String
): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index > 0) result.append(separator)
result.append(element)
}

result.append(postfix)
return result.toString()
}

// use case
val list = listOf(1, 2, 3)
println(joinToString(list, "; ", "(", ")"))
Read more

코틀린 기초

코틀린의 기초적인 내용들을 정리한다.

  • 함수, 변수
  • 클래스, 프로퍼티
  • enum, when
  • iteration
  • 예외처리

함수

두 값 중 큰 값을 반환하는, max 함수를 작성해보자.

1
2
3
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}

위 함수 처럼, 본문이 중괄호로 둘러싸안 함수를 “블록이 본문인 함수” 라고 한다.

1
fun max(a: Int, b: Int): Int = if (a > b) a else b

위 함수 처럼, 본문이 등호와 식으로 이루어진 함수를 “식이 본문인 함수” 라고 한다.
“식이 본문인 함수” 는 반환 타입을 작성하지 않아도 컴파일러가 식의 결과 타입을 반환 타입으로 지정한다.
이렇게 컴파일리거 타입을 분석해 프로그램 구성 요소의 타입을 지정하는 기능을 타입 추론이라고 한다.

그래서, 위 함수를 아래 처럼 수정할 수 있다.

1
fun max(a: Int, b: Int) = if (a > b) a else b
Read more

Spring Data JPA CRUD

Spring Data JPA 를 이용해서, repository 의 CRUD 를 직접 테스트한다.

Requirements

의존성을 다음과 같이 추가한다.

1
2
3
4
5
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

그리고, application.yml 에 다음과 같이 정의한다.
테스트 코드 실행시 수행된 SQL 을 확인하기 위함이다.

1
2
3
spring:
jpa:
show-sql: true

도서를 “생성/조회/수정/삭제” 하는 기능을 만들기 위해, Book 클래스를 정의하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Book {

@Id
@GeneratedValue
private Long id;

private String name;

public Book() {
}

public Book(String name) {
this.name = name;
}
}

그리고 repository interface 를 정의하자.

1
2
3
public interface BookRepository extends JpaRepository<Book, Long> {

}
Read more

Spring Kafka Listener Container BATCH AckMode

Spring Kafka Listener Container 의 AckMode 가 BATCH 일 때,
어떻게 records 를 consume 하고 commit 하는지 정리한다.

Offset

commit 을 정확히 이해하기 위해, offset 의 개념부터 정리하자.
Kafka 는 partition 의 각각의 record 에 대해 numerical offset 을 가지고 있다.
offset 은 두 가지 역할을 한다.

  1. partition 의 record 에 대한 unique identifier
  2. partition 에 대한 consumer 의 위치

그래서, commit 된 position 은 마지막 offset 을 가리킨다.

AckMode

Spring Kafka 에는 ContainerProperties 로 AckMode 일곱 가지가 있다.
offset commit 을 어떻게 할지에 대한 설정이다.
일곱 가지 중에 BATCH AckMode 는 어떻게 동작하는지 알아보자.

우선, BATCH AckMode 는 문서에 따르면 다음과 같이 정의되어 있다.

Commit the offsets of all records returned by the previous poll after they all have been processed by the listener.

번역하면 다음과 같다.
“이전 poll 에 의해 반환된 모든 레코드가” 리스너에 의해 모두 처리가 끝난 뒤에, offset 을 커밋한다.

Read more