-
변화하는 요구사항 대응하기 (사과 무게, 색에 따라 필터링 하기)
- 색을 파라미터화 (메소드 파라미터 추가)
- 가능한 모든 속성으로 필터링 (메소드 파마미터에 모두 추가)
-
동작 파라미타화
- 추상적 조건으로 필터링 (Predicate 사용)
- Predicate 란?
- 인수로 값을 받아 true or false 로 반환하는 함수를 predicate라 부른다.
- 제네릭을 사용해 사과 뿐만 아니라 모든 과일에서 유동적으로 필터링이 가능하게 만들었다.
-
복잡한 과정 단순화
- 익명 클래스
- Predicate 인터페이스를 구현하는 여러 클래스를 정의한 다음에 인스턴스화 해야 하는 번거로움이 있었다. 로직과 상관없는 코드들이 계속 발생하기 때문에 익명 클래스를 사용해 메소드 동작을 파라미터화 했다.
- 익명 클래스
-
요구 추가 (과일 무게순으로 정렬하기)
- Comparator (두 매개변수 객체를 비교) 정렬
-
compare(T o1, T o2) override 해 사용
-
o1.getXXX > o2.getXXX return 1; o1.getXXX == o2.getXXX return 0; o1.getXXx < o2.getXXX return -1;
-
- 람다 사용
- 람다 -> 메소드 참조 형식으로 변경
- Comparator (두 매개변수 객체를 비교) 정렬
- 메서드 내부적으로 다양한 동작을 수행할 수 있도록 코드를 메서드 인수로 전달.
- 1번과정을 추상화를 잘 시켜놓으면 변화하는 요구사항에 더 잘 대응할 수 있는 코드를 구현할 수 있다. 그렇게 되면 추 후 엔지니어링 비용을 줄일 수 있다.
- 코드 전달 기법을 이용해 메서드의 인수를 전달 할 수 있었지만. 추가로 구현해야 하는 코드들이 지저분 했다 인터페이스를 상속받아 여러 클래스를 구현해야 하는 수고를 덜어보자.
-
람다란?
- 메소드로 전달할 수 있는 익명 함수를 단순화 한 것. 이전 코드를 전달하는 과정에서 생성되는 코드들을 없애고 간결하고 유연하게 표현할 수 있다. 람다의 특징은 다음과 같다.
- 익명 : 보통의 메서드와 달리 이름이 없으므로 익명이라 표현
- 함수 : 람다는 메소드처럼 특정 클래스에 종속되지 않아 함수라 부른다.
- 전달 : 람다 표현식을 메서드 인수로 전달하거나 변수로 저장 할 수 있다.
- 메소드로 전달할 수 있는 익명 함수를 단순화 한 것. 이전 코드를 전달하는 과정에서 생성되는 코드들을 없애고 간결하고 유연하게 표현할 수 있다. 람다의 특징은 다음과 같다.
-
간결하게 표현할 수 있는 람다 어디에 어떻게 사용할까??
- 람다는 함수형 인터페이스 라는 문맥에서 람다 표현식을 사용할 수 있다.
-
함수형 인터페이스란??
- chapter1에서 Predicate[T] interface 로 필터 메서드를 파라미터화 했었다. 그렇다 Predicate[T] 가 함수형 인터페이스라 람다로 표현할 수 있었다. Predicate[T] 는 오직 하나의 추상 메서드만 지정한다.
- 다시말해 하나의 추상 메서드를 지정하는 인터페이스를 함수형 인터페이스라 부르고 현재까지 사용한 Java API 의 함수형 인터페이스는 Comparator, Runnable 있다.
- 람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 전체 표현식을 함수형 인터페이스의 인터페이스로 취급 (함수형 인터페이스를 구현한 클래스의 인스턴스) 한다.
- @FunctionalInterface
- 함수형 인터페이스임을 가르키는 어노테이션
- java 에 해당 어노테이션을 달 추상 메소드가 2개인 경우 에러가 발생한다.
-
람다 활용 : 실행 어라운드 패턴 (execute around pattern)
- 데이터 베이스 파일 처리 같이 사용하는 순환 패턴은 자원을 열고, 처리한 다음 자원을 닫는 순서로
이루어 진다. 설정과 정리 과정은 대부분 비슷하다.
즉. 실제 자원을 처리하는 코드를 설정과 정리 두 과정이 둘러싸는 형태를 갖는다.
(ReadProcess.class는 java7에 추가된 try-with-resources 구문 사용)
- 데이터 베이스 파일 처리 같이 사용하는 순환 패턴은 자원을 열고, 처리한 다음 자원을 닫는 순서로
이루어 진다. 설정과 정리 과정은 대부분 비슷하다.
-
BufferedReaderProcessorImpl은 @FucntionalInterface를 두가지 방법으로 구현했다.
- override
- 시그니처와 일치하는 함수형 인터페이스를 만들면 lambdaSampleFunction 처럼 메서드의 인수로 전달할 수 있다.
-
스트림 특징
- 멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있다.
- 딱 한 번만 탐색할 수 있다.
- 외부 반복과 내부 반복
- 중간 연산과 최종 연산
- 연결할 수 있는 스트림 연산을 중간 연산이라고 하며, 스트림을 닫는 연산을 최종 연산이라 한다.
중간 연산 : filter, map, limit, sorted, distinct 등..
최종 연산 : count, forEach, collect 등..
- 연결할 수 있는 스트림 연산을 중간 연산이라고 하며, 스트림을 닫는 연산을 최종 연산이라 한다.
- 스트림의 요소는 요청할 때 lazily(게으르게) 계산된다.
-
스트림을 왜 사용할까??
- 컬렉션 인터페이스를 사용하려면 사용자가 직접 요소를 반복해야 한다. 이 과정에서 사용자는 결과값을 어딘가에 저장해야 했다. 하지만 스트림을 사용하면 이러한 것들을 사용하지 않게 내부 반복을 사용한다.
- 전략패턴(Strategy Pattern) 특징
- 객체들이 할 수 있는 향위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화 하는 인터페이스 정의하여 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법
- if - else 분기 제거