이펙티브 자바의 아이템 42. 익명 클래스보다는 람다를 사용하라
를 학습한 내용입니다.
자바에서는 객체지향 언어다. 함수를 표현할 수 있는 타입이 따로 존재하지 않는다.
그래서 함수 타입을 표현하기 위해 함수형 인터페이스
를 사용한다.
추상 메소드
를 딱 하나만
갖고 있는 인터페이스를 함수형 인터페이스라고 부르기 시작했다.@FunctionalInterface
public interface ValueGenerator<T> {
T generate(int min, int max);
static void doSomething1() {
//...
}
default void doSomething2() {
//...
}
}
T generator(int min, int max)
와 같은 메소드를 정의해야 한다.public class IntegerValueGenerator implements ValueGenerator<Integer> {
Random random = new Randeom();
@Override
public Integer generate(int min, int max) {
return random.nextInt(max - min + 1) + min ;
}
}
public class Main {
public static void main(String[] args) {
ValueGenerator<Integer> valueGenerator = new IntegerValueGenerator<>();
}
}
선언
과 사용
을 동시에 하는 클래스public class Line {
private List<Bar> bars;
private Line() {}
public static Line create(int size, ValueGenerator<Integer> valueGenerator) {
Line line = new Line();
line.bars = new ArrayList<>();
for (int indexBars; indexBars < size; indexBars++) {
Bar bar = Bar.create(valueGenerator.generate(1, 2));
line.bars.add(bar);
}
retrun line;
}
}
Line line = Line.create(size, new ValueGenerator<Integer>() {
Random random = new Random();
public Integer generate(int min, int max) {
return random.nextInt(max - min + 1) + min ;
}
});
public enum Direction {
TURN_LEFT {
public int followDirection(int currPosition) {
return currPosition - 1;
}
},
TURN_RIGHT {
public int followDirection(int currPosition) {
return currPosition + 1;
}
},
GO_STRAIGHT {
public int followDirection(int currPosition) {
return currPosition;
}
};
public abstract int followDirection(int currPosition);
}
public enum Direction {
TURN_LEFT(new Positioning() {
public int followDirection(int currPosition) {
return currPosition - 1;
}
}),
TURN_RIGHT(new Positioning() {
public int followDirection(int currPosition) {
return currPosition + 1;
}
}),
GO_STRAIGHT(new Positioning() {
public int followDirection(int currPosition) {
return currPosition;
}
});
private final Positioning positioning;
Direction(Positioning positioning) {
this.positioning = positioning;
}
}
// --------------
@FunctionalInterface
public interface Positioning {
int followDirection(int currPosition);
}
람다식
이다.매개변수
, 반환값
일 수 있다.([타입] 파라미터1, [타입] 파라미터2, ...) -> { 실행 내용 }
@FunctionalInterface
public interface Calculator {
int calculate(int x, int y);
}
//기본
(int x, int y) -> {
System.out.println("람다식 호출");
return x + y;
}
//타입 생략 가능
(x, y) -> {return x + y;}
//실행부 문장이 1줄일 때 중괄호{}와 return을 생략 가능하다
(x, y) -> x + y
//매개변수 1개일 경우 소괄호() 생략 가능
x -> x + 1;
매개변수의 타입
이나 리턴 타입
을 입력하지 않아도 된다는 것이다.@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparator<Integer> comparator = (x, y) -> x - y;
public enum Direction {
TURN_LEFT(position -> position - 1),
TURN_RIGHT(position -> position + 1),
GO_STRAIGHT(position -> position);
private final Positioning positioning;
Direction(Positioning positioning) {
this.positioning = positioning;
}
}
// --------------
@FunctionalInterface
public interface Positioning {
int followDirection(int currPosition);
}
Postioning leftPositioning = position -> position - 1;
TURN_LEFT(new Positioning {
public int followDirection(int currPosition) {
System.out.println(this);
return currPosition - 1;
}
})
TURN_LEFT(position -> {
System.out.println(this);
return position - 1
})
public class AnonymousPositioning {
public static void main(String[] args) {
Positioning leftPositioning = new Positioning() {
@Override
public int followDirection(int currPosition) {
return currPosition + 1;
}
};
System.out.println(leftPositioning);
}
}
public class LambdaPositioning {
public static void main(String[] args) {
Positioning leftPositioning = x -> x + 1;
System.out.println(leftPositioning);
}
}
invokedynamic
은 런타임에 동적으로 클래스를 정의하고 인스턴스를 생성해서 반환하는 명세이다.익명 클래스의 경우 함수형 타입 자체를 정의하려고 사용하기 보단, 반복적으로 필요하지 않은 클래스를 인스턴스화할 때 사용하면 될 것이다.
또한, 람다식으로 표현하는데, 실행부가 너무 길어 복잡하거나 자기자신의 인스턴스를 참조해야될 일이 있다면 람다식 보다는 익명 클래스를 고려해보는 것이 좋겠다.
하지만, 함수 자체를 매개변수나 리턴 값으로 사용하기 위해서 표현해야된다면, 람다식을 사용하여 자바에서 폭넓은 함수형 프로그래밍을 할 수 있도록 한다.