썸넬 Image ref :
https://velog.io/@yjw8459/Java-Lambda%EB%9E%8C%EB%8B%A4
단 1개의 추상 메소드를 갖는 인터페이스를 말합니다. Java 8부터 인터페이스는 기본 구현체를 포함한 default method를 포함할 수 있습니다. 여러 개의 default or static method가 있더라도 추상 메소드가 오직 하나라면 함수형 인터페이스입니다. 자바의 람다 표현식은 함수형 인터페이스로만 사용 가능합니다.
ref : https://catsbi.oopy.io/e980e4b7-fde3-4ceb-91f9-181ce2e7b507#9a3554bd-1214-42f1-804d-bfb1764422bc
🔎 default and static method 의 개수가 상관없는 이유
Java 8 이전에는 익명 내부 클래스를 통해 함수형 인터페이스를 구현하여 사용했습니다. 하지만 Java 8 이후 람다표현식이 등장하여 간략하게 구현할 수 있게 되었습니다.
@FunctionalInterface
public interface RunSomething {
void doIt();
static void printName(){
System.out.println("catsbi");
}
default void printAge(){
System.out.println("33");
}
}
public class Foo {
public static void main(String[] args){
//A : Functional Interface
A a = new A() {
@Override
public void method() {...}
}
}
}
public class Foo{
public static void main(String[] args){
//A : Functional Interface
A a = () -> System.out.println("Anything");
}
}
함수형 인터페이스는 추상 메소드가 하나이기 때문에 람다식을 사용해도 해당 추상 메소드의 구현이라는 것을 인지합니다. 여기서 default 또는 static method가 여러 개 있어도 함수형 인터페이스는 성립합니다. 그 이유는 default 및 static method는 body가 있어야 하기 때문입니다. 즉, 람다식과 매칭되지 않아 몇 개를 사용해도 추상 메소드를 인지하지 못할 일이 없습니다.
@FunctionalInterface
해당 인터페이스가 함수형 인터페이스 조건에 맞는지 검사해줍니다. 이것이 없어도 함수형 인터페이스로 동작하지만, 인터페이스 검증과 유지보수를 위해 붙여주는 게 좋습니다.
Error Example : Multiple non-overriding abstract methods found in interface com.practice.notepad.CustomFunctionalInterface
ref : https://bcp0109.tistory.com/313
ref : https://catsbi.oopy.io/e980e4b7-fde3-4ceb-91f9-181ce2e7b507#9a3554bd-1214-42f1-804d-bfb1764422bc
인터페이스에 있는 구현 메소드를 의미합니다. 기존의 추상 메소드와 다른 점은 default 예약어가 붙고, 구현부가 있어야 한다는 것입니다.
디폴트 메소드는 구현이 필수가 아니므로 인터페이스에 구현 메소드가 추가되었을 때, 모든 구현체마다 구현해야 하는 문제점을 해결할 수 있어 인터페이스 확장성을 높이고 OCP(개방-폐쇄 원칙)도 지킬 수 있도록 합니다.
default method 는 다음 2가지 충돌 상황이 발생할 수 있습니다.
이 때는, 인터페이스를 구현하는 클래스에서 default method를 재정의하면 해결할 수 있습니다. default method의 override는 필수가 아니지만 static과 달리 사용이 불가능한 것은 아닙니다.
ref : https://velog.io/@heoseungyeon/%EB%94%94%ED%8F%B4%ED%8A%B8-%EB%A9%94%EC%84%9C%EB%93%9CDefault-Method
매개변수를 받아 boolean값을 반환하는 함수형 인터페이스
즉, 내부 로직에 따라 매개변수를 넣어 연산한 후 그 결과를 true or false로 반환
test 또는 stream 필터링용으로 사용함
@Test
public void test() {
Predicate<Integer> predicate = (num) -> num < 10;
assertThat(predicate.test(5)).isTrue();
}
@Test
public void test() {
Predicate<Integer> predicate1 = (num) -> num < 10;
Predicate<Integer> predicate2 = (num) -> num > 5;
assertThat(predicate1.and(predicate2).test(7)).isTrue();
}
negate()
!test() 결과를 반환하는 Predicate 생성
@Test
public void test() {
Predicate<Integer> originPredicate = (num) -> num < 10;
Predicate<Integer> negatePredicate = originPredicate.negate();
assertThat(negatePredicate.test(5)).isFalse();
}
@Test
public void test() {
Predicate<Integer> predicate1 = (num) -> num < 10;
Predicate<Integer> predicate2 = (num) -> num > 5;
assertThat(predicate1.or(predicate2).test(3)).isTrue(); // predicate1만 충족
assertThat(predicate1.or(predicate2).test(12)).isTrue(); // predicate2만 충족
}
isEqual()
두 객체가 동일한지 판단 (Stream에서 사용 가능)
@Test
public void test1() {
Predicate<Integer> predicate = Predicate.isEqual(5);
assertThat(predicate.test(5)).isTrue();
assertThat(predicate.test(6)).isFalse();
}
@Test
public void test2() {
Stream<Integer> stream = IntStream.range(1, 10).boxed();
stream.filter(Predicate.isEqual(5))
.forEach(System.out::println);
}