Item9. try-finally 보다는 try-with-resource를 사용하라.

코딩을 하다보면 close method를 통해 반환해주어야 하는 리소스가 많다(java.sql.Connection, java.io 관련 리소스 ex) InputStream,OutputStream ) , 개발자가 실수로 리소스 정리를 깜빡하는 경우가 있다.

주로 자원을 반환할떄 사용하던 try- finally 구문은 다음과 같다.

1
2
3
4
5
6
7
8
9

static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try{
return br.readLine();
} finally {
br.close();
}
}

위 try - finally 의 단점은 다음과 같다.

  • 중첩 try - finally 문 작성으로 코드가 장황해지고, 디버깅이 힘들어질수 있다.
Read more

Item8. finalizer와 cleaner 사용을 피해라

Java는 두가지 객체 소멸자를 제공한다.

  1. finalizer

  2. cleaner

여기서 객체 소멸자란 생성자와 정반대의 개념으로, 객체가 소멸될떄(GC될때)
자동으로 호출되는 함수이다.

Java 9에서부터는 finalizer를 사용 자제해야 할 API로 지정하고, cleaner를 그 대안으로 소개하였다. 하지만 책에서는 cleaner또는 finalizer의 사용을 피하라고 얘기하고 있다,.그렇다면 finalizer와 cleaner는 왜 사용하면 안될까?

1
2
3
4
5
@Override // deprecated 
protected void finalize() throws Throwable {
super.finalize();
}

단점 1. finalizer와 cleaner는 즉시 수행된다는 보장이 없다.

객체의 소멸을 GC가 담당하므로, finalizer와 cleaner를 언제 수행할지의 역할은 전적으로 GC 알고리즘에 달려있다. 즉 GC 구현마다 차이가 있다.

위와 같은 특징들을 보면 당연히 finalizer와 cleaner로는 제때 실행되어야 하는 작업은 절대 할 수 없다.

단점 2. finalizer는 instance 반납을 지연시킬 수도 있다.

finalizer 쓰레드는 우선순위가 낮아서 , 언제 실행될지 모른다. -> 계속 대기 된다면 GC되지 않고, OutOfMemoryException이 발생할수도 있다.

단점 3. finalize 동작 중에 발생한 에러는 무시되며, 처리할 작업이 남았더라도, 그 순간 종료된다.

중간에 예외가 터지면, 객체가 훼손된 상태로 남아있을수도 있다.

단점 4. 성능 문제

AutoCloseable 객체를 만들고, try-with-resoucre 로 자원 반납을 하는데 걸리는 시간은 12ns 인데 비해, Finalizer는 550ns 거의 약 50배가 걸렸다. cleaner도 60ns로, 5배정도 느리다.

그렇다면 finalizer나 cleaner를 어떻게 대체해주어야 하는가?

  • 반환할 자원 class에 AutoCloseable 을 구현해주고, client에서 instance를 다 쓰고 나면 close method을 호출해주면 된다.

finalizer와 cleaner의 적절한 용도

  1. 자원 소유자가 close method를 깜빡하고 호출하지 못하였을때, 안전망 역할을 해준다.

  2. 자바 객체가 아닌 native peer 회수

cleaner 사용예시 - 리소스 반환을 위한 안전망 역할

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41


public class Room implements AutoCloseable{


private static final Cleaner cleaner = Cleaner.create();



private static class State implements Runnable{
int numJunkPiles; //

public State(int numJunkPiles) {
this.numJunkPiles = numJunkPiles;
}

@Override
public void run() {
System.out.println("clean room");
numJunkPiles = 0;
}
}

private final State state;

private final Cleaner.Cleanable cleanable;

public Room(int junk) {
state = new State(junk);
cleanable = cleaner.register(this,state);
}


@Override
public void close() throws Exception {
// 자원 사용하는 client가 리소스를 깜빡하고 반환하지 못하였을때, cleaner가 안전망 역할로써 이를 반환해준다 (gc될떄 호출됨 )
cleanable.clean();
}
}


위 예시처럼 Room client가 명시적으로 close를 호출하는것을 깜빡하였다면 room이 GC에 의해 회수될때 cleaner가 state의 run method를 호출해줌으로서 , 리소스를 회수하는 역할을 해준다. (안전망 역할)

하지만 이조차도 try-with-resouces 블록으로 감싸면 필요하지 않다.

예를 들면 다음과 같다.

1
2
3
4
5
6
7

public static void main(String[] args) throws Exception {
try(Room myRoom = new Room(8)){
new Room(99);
System.out.println(" try - with -resource " );
}
}

정리하면 java 8 : finalizer / java 9 이후 : cleaner는 안전망 역할이나 네이티브 피어 객체 회수용 정도로만 사용하고, 이후에는 사용하지 말고, 대신 try-with-resource로 안전하게 자원을 반환하자는 내용이다.

kotlin에서 null type 다루기

코틀린에서 Null type 허용하는 방법

1
2
3
4
5
fun test() {
val name = "dolly";
name =null;
// compile error
}

변수에 null을 할당 가능하게 하려면 다음과 같이 변수의 타입을 정의할떄, 물음표를 추가하면 된다.

1
2
3
4
5
6
7
8
class Person ( val first: String ,
// middle 변수에 null값이 들어갈수도있음.
val middle: String? ,
val last: String) {

val jkRolling = Person("Joanne",null,"Rowling")
val northWest = Person("North",null,"West")
}

코틀린은 nullable한 String? 이 null값이 아님이 보증이 되면 String type으로 smart cast 해준다.

Read more

spring type converter

spring 은 converter 인터페이스를 제공하여, 개발자가 spring에 추가적인 type 변환이 필요하면 이를 구현해서 등록할 수 있도록 지원해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

package org.springframework.core.convert.converter;

/**
* A converter converts a source object of type {@code S} to a target of type {@code T}.
*/
@FunctionalInterface
public interface Converter<S, T> {

/**
* Convert the source object of type {@code S} to target type {@code T}.
* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
* @return the converted object, which must be an instance of {@code T} (potentially {@code null})
* @throws IllegalArgumentException if the source cannot be converted to the desired target type
*/
@Nullable
T convert(S source);
Read more

spring api 에러 처리

API 예외처리는 단순히 오류 페이지를 반환하는 것보다 서버간 통신 규약에 따라 오류 응답 스펙을 정해놓고, JSON (또는 XML등 ) 으로 데이터를 내려준다.

API 예외 처리도 스프링 부트가 기본으로 제공하는 BasicErrorController 을 사용할 수 있긴하지만, 서버간 통신규약에 맞게 json을 반환하려면 customizing 할 수 있어야 한다.

Read more

spring error page 설정 , 예외 처리

servlet의 예외 발생 방식

  1. Exception
  2. response.sendError(http 상태코드, 오류 메시지 )

1. Exception

  • web app에서 예외 발생시 상황
  • 사용자 요청별로 별도의 쓰레드 할당
  • 특정 사용자 요청시 예외 발생 -> try~catch 문으로 예외 처리를 해주지 않는 경우 WAS까지 예외가 전달된다.
1
2
3

controller(예외 발생) -> interceptor -> dispatcher servlet -> filter -> WAS (예외 전달 )

Read more

spring filter vs interceptor

  • application 여러 로직에서 공통으로 포함되어 있는 로직을 공통 관심사 (cross-cutting concern)이라고 한다.

  • 웹 앱과 관련된 (ex) 로그인 ) 공통 관심사를 처리하는데, 주로 servlet filter 나, spring interceptor를 사용한다.

Read more

TDD (테스트 주도 개발, Test Driven Development) 와 JUnit

TDD란?

  • 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법
  • 테스트 코드가 기능 정의서처럼 기능함
  • 테스트를 먼저 만들고, 테스트가 성공하도록 하는 코드를 만드는 식으로 진행하기 때문에, Test coverage 영역이 높아진다.
  • 테스트를 작성하는 시간과, application 코드를 작성하는 시간의 간격이 짧아진다.
Read more

spring batch (1)

배치 처리란?

  • 일반적인 GUI를 가진 app은 사용자와 상호작용함
  • 사용자와 상호작용없이 유한한 양의 데이터를 처리하는 것 (GUI없음)
Read more