java8
자바8의 새롭게 바뀐 부분이 많지만 그 중 내가 자주 쓰는걸 정리 해보겠다.
@FunctionalInterface
첫 번째로
@FunctionalInterface
인터페이스다.
람다를 쓰긴 위한 애노테이션이다. 만약 저 애노테이션이 붙은거라면 람다 표현식을 사용 할 수 있다.
하지만 명시적으로 지정 하지 않더라도
abstract
메소드가 한개라면 람바 표현식을 사용 할 수 있다.
만약 저 애노테이션을 사용한다면 abstract 메소드가 2개 이상 있을경우 컴파일 타임에 에러가 난다.
자바 기본 패키지에 있는
Function
이라는 인터페이스다.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
//...
}
한번 커스텀한 interface를 만들어보자.
두개의 같은 타입 파라미터를 넘겨서 두개를 더하는 인터페이스다.
@FunctionalInterface
interface AddFunction<T> {
T apply(T t, T t1);
}
사용해 보자
AddFunction<Integer> add = (i, j) -> i + j;
System.out.println(add.apply(10, 20));
AddFunction<String> add1 = (i, j) -> i + j;
System.out.println(add1.apply("hello", " world"));
결과는 다음과 같을 것이다.
30
hello world
lambda
두 번째론 람다표현식이다. 자바 개발자 한테는 조금 생소한 표현식 이다. 하지만 다른 언어들은 일찌감치 람다 표현식을 사용하고 있다.
스칼라, 파이썬 하스켈, c#등 여러가지 언어에서 사용 하고 있다.
한번 살펴보자.
우리가 쓰레드를 사용 할때 이용하는 인터페이스중
Runnable
가 있다. 이 것도 java8에선 FunctionalInterface로 구현되었다.
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
우리가 java8 이전에는 이렇게 사용하곤 했다. 우리가 흔히 말하는 익명 클래스다. 예를 든 코드다 실질적으로 이렇게 사용하진 않는다.
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("run 호출");
}
};
runnable.run();
그런데 람바를 쓰면 아주 간단하게 바뀐다. 한번보자.
Runnable runnable = () -> System.out.println("run 호출");
runnable.run();
6줄을 단 한줄로 바꿔버렸다. 대단하다.
그럼 어떻게 바뀌는지 한번 보자.
()
이거는 파라미터다
Runnable
의
abstract
메소드
run
은 받는 파라미터가 한개도 없다. 그래서 괄호만 해주는거다.
->
애로우?라 부른다? 람다? 인가? 흠 그리고 다음 나오는게 메소드 바디이다. 간단하다.
그럼 다음 예제도 살펴보자
이번엔 아까 위에서 봤던
Function
인터페이스다. 이 인터페이스를 아마 자주 사용할 듯 하다.
일단 람다를 쓰지말고 한번 해보자.
Function<Integer,String> function = new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return String.valueOf(integer);
}
};
String str = function.apply(1010);
System.out.println(str);
일단 Function 인터페이스는 제네릭타입이다. 첫 번째는 파라미터타입 두 번째는 리턴 타입이다.
한마디로 어떤 타입의 파라미터로 넘기면 다른 타입을 반환하는걸 의미한다. 같은 타입을 지정해도 상관없다. 이런걸
identity
라 부른다.
위의 코드는 int를 String으로 변환하는 코드다.
이제 람다로 바꿔보자!
Function<Integer,String> function = x -> String.valueOf(x);
String str = function.apply(1010);
System.out.println(str);
이것도 아주 깔끔하고 짧게 바뀌었다.
다시 한번 살펴보자.
apply
메소드는 파라미터가 한개다.그래서
x
라는 변수 한개를 선언했다.(파라미터가 한개일땐
()
로 감싸주지 않아도 된다.)
그리고 그
x
로 String.valuOf를 이용하여 변환 하였다.
그런데
String.valueOf
를 호출하기전에 그 파라미터가 어떤건지 한번
Print
로 출력하고 싶다.
그럼 메소드 바디를 감싸주면 된다. 컬리브레이스로 감싸자 해보자.
Function<Integer,String> function = x -> {
System.out.println(x);
return String.valueOf(x);
};
이외에도 자주 쓰는 인터페이스는
Consumer<T>
어떤 타입의 파라미터로 받는다 리턴은 없다.
Predicate<T>
어떤 타입의 파라미터로 받는다 리턴은 Boolean 이다.
Supplier<T>
어떤 타입으로 리턴한다. 파라미터는 없다.
이 외에도
java.util.function
패키지에 가보면 function 인터페이스가 있다. 한번씩 보자!
다음 시간에
Stream
을 공부해보겠다.