함수형 인터페이스
추상 메소드를 하나만 가지고 있는 인터페이스입니다.
함수형 인터페이스를 정의하기 위해 @FunctionalInterface 애노테이션을 사용할 수 있습니다.
이 애노테이션은 자바에서 제공해줍니다.
java 8부터 인터페이스이지만 메서드안에 구현체가 있을 수 있고 default 메서드를 추가할 수도 있게 변경됐습니다.
<예제1> - 함수형 인터페이스
public interface RunSomething {
void doIt();
//구현부가 있는 메서드
static void printName(){
System.out.println("dayeon");
}
//디폴트 메서드
default void printAge(){
System.out.println("20");
}
}
RunSomething 인터페이스는 doIt이라는 추상 메소드를 하나만 가지고 있습니다.
pringName과 printAge 디폴트 메소드가 있지만 추상 메소드는 하나이므로 함수형 인터페이스라고 할 수 있습니다.
@FunctionalInterface 애노테이션을 이용하여 함수형 인터페이스라는 것을 명시하고 있습니다.
현재 추상 메소드가 2개이므로 'Multiple non-overriding abstract methods found in interface RunSomething'
에러가 납니다.
<예제2> - @FunctionalInterface 사용
@FunctionalInterface
public interface RunSomething {
void doIt();
void doIt2(); // 추상메서드가 2개인 상태
static void printName(){
System.out.println("dayeon");
}
default void printAge(){
System.out.println("20");
}
}
람다 표현식
람다를 자바에서는 특수한 형태의 오브젝트로 보고 있습니다. 이러한 오브젝트를 메소드 매개변수, 리턴 타입, 변수로 만들어서 사용할 수 있습니다.
함수형 인터페이스의 인스턴스를 만드는 방법으로 람다 표현식이 쓰일 수 있습니다.
아래 예제는 Runsomething클래스의 doIt 메소드를 오버라이딩 하고 있는 익명 내부 클래스입니다.
<예제3> - 람다 표현식을 사용하지 않은 익명 내부 클래스
public class Foo {
public static void main(String[] args) {
//익명 내부 클래스 anonymous inner class
RunSomething runSomething = new RunSomething() {
@Override
public void doIt() {
System.out.println("Hello");
}
};
}
}
자바8 부터는 람다 표현식을 이용하여 간결하게 표현할 수 있게 해줍니다.
<예제4> - 람다 표현식을 사용하여 표현
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = () -> System.out.println("Hello");
}
}
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = () -> System.out.println("Hello");
runSomething.doIt();
}
}
runSomething.doIt()으로 메소드를 실행할 수 있습니다.
<예제5> - 람다 표현식 예
메소드가 두 줄 이상일 때는 {} 를 사용합니다.
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = new RunSomething() {
@Override
public void doIt() {
System.out.println("Hello");
System.out.println("람다 두 줄일 때");
}
};
}
}
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = () -> {
System.out.println("Hello");
System.out.println("람다 두 줄일 때");
};
}
}
자바에서 함수형 프로그래밍
first class object
first class object란?
- 파라미터로 전달할 수 있다.
- 반환값으로 사용할 수 있다.
- 변수나 데이터 구조 안에 담을 수 있다.
자바는 보통 Object(객체)가 위 기능들을 수행했지만 자바8 부터는 함수형 프로그래밍을 지원하므로 메소드를 first-class-object로 사용할 수 있게 되었습니다.
순수함수 (Pure Function)
외부의 상태를 변경하거나 함수로 들어온 인자의 상태를 직접 변경하지 않고,
어떤 함수에 동일한 인자를 주었을 때 항상 같은 값을 리턴하는 함수입니다.
--> 외부의 값을 참조하거나 변경하지 않는 함수
<예제6> - 순수함수
@FunctionalInterface
public interface RunSomething {
int doIt(int number);
}
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = (number) -> number + 10;
}
}
예제3의 경우 동일한 number 인자에 대해서 항상 같은 값을 리턴한다고 기대할 수 있으며 외부의 상태를 변경하는 것이 없어 순수함수라고 할 수 있습니다.
<예제7> - 순수함수가 아닌 경우
public class Foo {
int baseNumber = 10;
public static void main(String[] args) {
int baseNumber2 = 20;
RunSomething runSomething = (number) -> number + baseNumber + baseNumber2;
}
}
baseNumber, baseNumber2와 같은 함수 밖의 값을 참조해서 쓰는 경우 상태값을 가지고 있다 또는 상태값에 의존한다고 하며 순수함수라고 할 수 없습니다.
<예제8> - 순수함수가 아닌 경우2
public class Foo {
public static void main(String[] args) {
RunSomething runSomething = new RunSomething() {
int num = 30;
@Override
public int doIt(int number) {
num++;
return 0;
}
};
}
}
doIt 메서드 밖에서 선언한 num 변수의 값을 메서드에서 변경하고 있습니다. 외부 값을 변경하고 있으므로 순수 함수라고 볼 수 없습니다.
'Java' 카테고리의 다른 글
java length (0) | 2021.08.20 |
---|---|
[Java] 컴파일러 vs 인터프리터 vs JIT compiler (0) | 2021.05.31 |
[Java] JVM 구조와 원리 (0) | 2021.05.23 |
[Java] Static 변수, static 메소드 (0) | 2021.05.23 |
[Java] String, StringBuffer, StringBuilder (1) | 2021.04.22 |