Functional Programming in Java 8 책의 6장에 Lambda를 이용하여 Lazy Initialization을 하는 방법이 나온다.

이 예제는 Heavy 객체의 생성을 Supplier 인터페이스를 이용해서 사용할 시점까지 지연시키는 예제다.

하지만 이 예제는 Heavy 클래스가 아닌 또 다른 heavy한 객체를 생성해야 할 때 매번 해당 클래스에 대한 HeavyInstanceHolder 클래스를 만들어 주어햐 하는 단점이 있다.

Jake라는 분이 이를 해결한 방법 Blog로 정리해 놓았다. 요점은 Heavy 클래스를 Lazy로 생성하는 부분을 T 형 타입으로 받아서 처리하면 된다.
그런데 synchronized 키워드를 붙여 thread-safe 하게 처리한 부분이 좀 이상해서 github을 따라 갔더니 코드가 조금 변경되어 있다.

해당 github 소스:

- test용 main 클래스
- Lazy Initialization 구현 클래스


하지만 여전히 문제가 있다. main 클래스에서 Heavy 객체를 생성하는 게 잘 표현되어 있지 않다!! Venkat(책 저자)의 의도가 드러나게 다시 바꿔보자.


먼저 초기화에 시간이 오래 걸리는 Heavy 클래스가 있다.


이 놈을 여러번 생성하는 테스트 클래스다. 2개의 쓰레드에서 Heavy 객체를 동시에 생성해 보자. 그리고 생성 후 Heavy 객체의 메소드를 호출해서 2번째 쓰레드가 같은 객체를 또 생성하지는 않는지, 지연 생성이 완료될 때까지 기다리고 있는 지도 확인 해 보자.


LazilyInstantiate 클래스다. Supplier를 이용해서 Heavy 생성 시점을 지연시키고, 한 번 생성된 객체는 재활용한다.


Main을 실행한 결과

Main start
Thread1 run
Main end
Thread2 run
Heavy Initiation started from Thread1
Heavy Initiation ended from Thread1
1
2


이제 Main 함수에서 Heavy 객체 외에 다른 객체(Heavy2)의 생성을 지연시키고 싶다면, 이렇게만 하면 된다.



Files 클래스에는 Java 8에서 추가된 find라는 메소드가 있다.

Funtional Programmin in Java 8 책의 3장에 ListSubDir.java 예제가 있는데,  해당 디렉토리의 하부 디렉토리까지만 가져오므로 완전한 예가 아니다.

find를 이용해서 어떤 디렉토리에 존재하는 모든 파일을 가져오도록 Stream API를 이용하여 작성해 보자.

Path start = Paths.get(".");

int maxDepth = 5; // Integer.MAX_VALUE로 하면 모든 파일을 가져올 수 있다

Files.find(start, maxDepth, (path, attr) -> true)

        .forEach(System.out::println);

만약 어떤 특정 파일 속성을 가지는 파일만 가져오고 싶다면 find의 3번째 인자를 수정하면 된다.

예를 들어 .java파일만 찾고 싶다면

(path, attr) -> path.toString().endsWith(".java")

이렇게 바꿔주면 된다.



제목: 자바 8 람다의 힘 / Functional Programming in Java 8

저자: 벤컷 수브라마니암(Venkat Subramaniam)

출판사: 루비페이퍼


함수형 스타일 코드의 큰 이점

1. 변수의 명시적인 변경이나 재할당 문제를 피할 수 있다.

2. 쉽게 병렬화(멀티 쓰레딩)가 가능하다.

3. 서술적인 코드의 작성이 가능하다.

4. 더 '간결'하다. (짧고, 오류가 없고, 개발자의 의도를 효과적으로 전달한다)

5. 직관적이다. 사람이 문제를 설명하는 방식대로 코드를 작성한다.

ex)


함수형 인터페이스: 추상메서드가 하나인 인터페이스

ex) Runnable, Callable, Comparable

유용한 함수형 인터페이스: Consumer<T>, Supplier<T>, Predicate<T>, Function<T, R>