람다(Lambda)

김주영·2022년 11월 5일
0

자바 <면접>

목록 보기
2/9
post-thumbnail

썸넬 Image ref :
https://velog.io/@yjw8459/Java-Lambda%EB%9E%8C%EB%8B%A4

🌱 함수형 인터페이스(Functional Interface)


단 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 Method)

인터페이스에 있는 구현 메소드를 의미합니다. 기존의 추상 메소드와 다른 점은 default 예약어가 붙고, 구현부가 있어야 한다는 것입니다.

📌 장점

디폴트 메소드는 구현이 필수가 아니므로 인터페이스에 구현 메소드가 추가되었을 때, 모든 구현체마다 구현해야 하는 문제점을 해결할 수 있어 인터페이스 확장성을 높이고 OCP(개방-폐쇄 원칙)도 지킬 수 있도록 합니다.

📌 충돌

default method 는 다음 2가지 충돌 상황이 발생할 수 있습니다.

  1. 여러 인터페이스의 디폴트 메소드 간의 충돌
  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

🌱 Predicate


매개변수를 받아 boolean값을 반환하는 함수형 인터페이스
즉, 내부 로직에 따라 매개변수를 넣어 연산한 후 그 결과를 true or false로 반환

test 또는 stream 필터링용으로 사용함

  • test()
@Test
public void test() {
    Predicate<Integer> predicate = (num) -> num < 10;
    assertThat(predicate.test(5)).isTrue();
}
  • and()
@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();
}
  • or()
@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);
}

ref : https://yeonyeon.tistory.com/200

0개의 댓글