티스토리 뷰
42 익명 클래스보다는 람다를 사용하라
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
위 코드는 문자열을 길이순으로 정렬한다. 이 때, 정렬을 위한 비교 함수로 익명 클래스를 사용한다.
익명 클래스 방식은 코드가 너무 길기 때문에 함수형 프로그래밍에 적합하지 않아 보인다.
위 코드를 람다로 바꾼 모습을 살펴보자.
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
여기서 람다, 매개변수, 반환값의 타입은 각각 Compare<String>, String, int지만 코드에서는 언급이 없다. 타입을 명시해야 코드가 더 명확할 때를 제외하곤 람다의 모든 매개변수 타입은 생략하자.
람다 자리에 비교 생성 메서드를 사용하면 이 코드를 더 간결하게 만들 수 있다.
Collections.sort(words, comparingInt(String::length));
자바8에 List 인터페이스에 추가된 sort 메서드를 이용하면 더욱 짧아진다.
words.sord(comparingInt(String::length);
아이템 34에서 작성한 enum 코드를 람다로 변환해보자.
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
public abstract double apply(double x, double y);
}
*열거 타입 생성자 안의 람다는 열거 타입의 인스턴스 멤버에 접근할 수 없다(인스턴스는 런타임에 만들어지기 때문이다.)
람다가 대체할 수 없는 익명 클래스의 역할은 다음과 같다.
- 추상 클래스의 인스턴스를 만들 때 람다를 쓸 수 없으니, 익명 클래스를 써야 한다.
- 추상 메서드가 여러 개인 인터페이스의 인스턴스를 만들 때도 익명 클래스를 쓸 수 있다.
- 람다는 자신을 참조할 수 없다. 람다의 this 키워드는 바깥 인스턴스를 가리키고, 익명 클래스에서의 this는 익명 클래스의 인스턴스 자신을 가리킨다.
43 람다보다는 메서드 참조를 사용하라
람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함이다. 그런데 자바에는 함수 객체를 심지어 람다보다도 더 간결하게 만드는 방법이 있으니, 바로 메서드 참조다.
다음 코드는 임의의 키와 Integer 값의 매핑을 관리하는 프로그램의 일부다.
이 때, 값이 키의 인스턴스 개수로 해석된다면, 이 프로그램을 멀티셋을 구현한게 된다.
이 코드는 키가 맵 안에 없다면 키와 숫자 1을 매핑하고 이미 있다면 기존 매핑 값을 증가시킨다.
map.merge(key, 1, (count, incr) -> count + incr);
merge 메서드는 키, 값, 함수를 인수로 받으며 주어진 키가 맵 안에 아직 없다면 주어킨 {키, 값} 쌍을 그대로 저장한다. 반대로 키가 이미 있다면 {키, 함수의 결과} 쌍을 저장한다. 깔끔해 보이는 코드지만 매개변수인 count와 incr은 크게 하는 일 없이 공간을 꽤 차지한다.
람다 대신 이 메서드의 참조를 전달하면 똑같은 결과를 더 보기 좋게 얻을 수 있다.
map.merge(key, 1, Integer::sum);
IDE는 람다를 메서드 참조로 대체하라고 권할 텐데, 항상 이쪽이 이득인 것은 아니다.
예를 들어 GoshThisClassNameIsHumongous 클래스 안에 다음 코드가 있다고 가정해보자.
service.execute(GoshThisClassNameIsHumongous::action);
이를 람다로 대체하면 다음처럼 된다.
service.execute(() -> action());
45 스트림은 주의해서 사용하라
스트림의 핵심은 두 가지다.
- 스트림(stream)은 데이터 원소의 유한 혹은 무한 시퀀스(sequence)를 뜻한다.
- 스트림 파이프라인(stream pipeline)은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다.
스트림 안의 데이터 원소들은 객체 참조나 한정적인 기본 타입(int, long, double)이다.
스트림 파이프라인은 소스 스트림에서 시작해 종단 연산(terminal operation)으로 끝나며 그 사이에 하나 이상의 중단 연산(intermediate operation)이 있을 수 있다.
각 중단 연산은 스트림을 어떠한 방식으로 변환한다. 변환된 스트림의 원소 타입은 변환 전 스트림의 원소 타입과 같을 수도 있고 다를 수도 있다.
종단 연산은 마지막 중간 연산이 내놓은 스트림에 최후의 연산을 가한다.
스트림 파이프라인은 지연평가(lazy evaluation)된다. 평가는 종단 연산이 호출될 때 이뤄지며, 종단 연산에 쓰이지 않는 데이터 원소는 계산에 쓰이지 않는다.
스트림 API는 메서드 체인을 지원하는 fluent API다.
스트림 파이프라인은 기본적으로 순차적으로 수행된다. 파이프라인을 병렬로 실행하려면 스트림 중 하나에서 parallel 메서드를 호출하면 되나, 효율적인 상황은 많지 않다.
다음 상황은 스트림을 사용하기에 안성맞춤인 상황이다.
- 원소들의 시퀀스를 일관되게 변환한다.
- 원소들의 시퀀스를 필터링한다
- 원소들의 시퀀스를 하나의 연산을 사용해 결합한다(더하기, 연결하기, 최솟값 구하기 등)
- 원소들의 시퀀스를 컬렉션에 모은다(아마도 공통된 속성을 기준으로 묶어가며)
- 원소들의 시퀀스에서 특정 조건을 만족하는 원소를 찾는다
'프로그래밍 > 책' 카테고리의 다른 글
[이펙티브 자바, Effeective Java] 9장 일반적인 프로그래밍 원칙 (0) | 2022.01.25 |
---|---|
[이펙티브 자바, Effeective Java] 8장 메서드 (0) | 2022.01.19 |
[이펙티브 자바, Effeective Java] 6장 열거 타입과 어노테이션 (0) | 2021.12.28 |
[이펙티브 자바, Effeective Java] 5장 제네릭 (0) | 2021.12.22 |
[이펙티브 자바, Effeective Java] 4장 클래스와 인터페이스 (1) | 2021.12.20 |
- Total
- Today
- Yesterday
- spring boot
- nginx 톰캣 설정
- 국비 프로젝트
- java.lang.AbstractMethodError
- github webhook jenkins
- webhook
- 깃허브 웹훅 젠킨스
- springboot
- HTML
- 스프링부트 젠킨스
- jenkins webhook
- nginx 내장톰캣 설정
- 토이프로젝트 회고
- 오라클
- CI/CD
- oracle.jdbc.driver.T4CConnection.isValid(I)Z
- github webhook
- 스프링부트 자동배포
- nginx 내장톰캣 연결
- springboot jpa
- slack
- GitHub
- 젠킨스 웹훅
- nginx to tomcat
- 오라클 계정 오류
- nginx to 내장톰캣
- nginx to springboot tomcat
- oracle
- spring boot jenkins
- 젠킨스 자동 배포
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |