익명 클래스(Anonymous Class)는 일반적으로 인터페이스나 추상 클래스를 익명으로 구현하거나 확장하는 방식으로 사용됩니다. 이 때문에 익명 클래스를 사용하면 하나의 상속받은 클래스를 만드는 것과 유사한 동작을 수행하게 됩니다.
예를 들어, 다음은 인터페이스를 익명으로 구현하는 익명 클래스의 예입니다:
public interface MyInterface {
void myMethod();
}
public class Main {
public static void main(String[] args) {
// 익명 클래스를 사용하여 MyInterface를 구현
MyInterface myInterface = new MyInterface() {
@Override
public void myMethod() {
System.out.println("Implementation of myMethod");
}
};
// 익명 클래스의 메서드 호출
myInterface.myMethod();
}
}
위의 코드에서 익명 클래스는 MyInterface를 구현하고 있습니다. 이 익명 클래스는 인터페이스의 메서드를 구현하고 그 인스턴스를 생성하는 것과 같은 효과를 가지고 있습니다.
유사하게, 추상 클래스를 익명으로 확장할 수도 있습니다. 다음은 익명 클래스가 추상 클래스를 확장하는 예입니다:
public abstract class MyAbstractClass {
abstract void myAbstractMethod();
}
public class Main {
public static void main(String[] args) {
// 익명 클래스를 사용하여 MyAbstractClass를 확장
MyAbstractClass myAbstractClass = new MyAbstractClass() {
@Override
void myAbstractMethod() {
System.out.println("Implementation of myAbstractMethod");
}
};
// 익명 클래스의 메서드 호출
myAbstractClass.myAbstractMethod();
}
}
익명 클래스를 사용하면 클래스를 정의하고 동시에 인스턴스를 생성할 수 있으며, 일회성으로 사용되는 간단한 구현을 표현하는 데 효과적입니다.
++
람다 표현식 != 함수형 인터페이스
람다 표현식은 추상 메서드가 1개만 있는 인터페이스에 모두 사용가능.
함수형 인터페이스는 추상 메서드 1개만 가지고 있어야 함.
인터페이스에서 추상 메서드가 하나만 있는 경우, 해당 인터페이스를 "Functional Interface(함수형 인터페이스)"라고 부릅니다. 함수형 인터페이스는 Java에서 함수형 프로그래밍을 지원하는 중요한 개념 중 하나입니다.
Java에서는 함수형 인터페이스를 정의하기 위해 @FunctionalInterface 어노테이션을 제공합니다. 이 어노테이션을 사용하면 컴파일러가 해당 인터페이스가 함수형 인터페이스의 규칙을 따르는지를 체크해줍니다.
간단한 함수형 인터페이스의 예시를 살펴보겠습니다:
@FunctionalInterface
interface MyFunctionalInterface {
// 추상 메서드가 하나만 있음
void myMethod();
// 함수형 인터페이스에서는 default 메서드나
static 메서드가 여러 개 있어도 상관 없음
default void anotherMethod() {
System.out.println("Default method");
}
}
public class Main {
public static void main(String[] args) {
// 람다 표현식을 사용하여 함수형 인터페이스의 객체 생성
MyFunctionalInterface functionalInterface = () -> {
System.out.println("Implementation of myMethod");
};
// 함수형 인터페이스의 메서드 호출
functionalInterface.myMethod();
}
}
위의 코드에서 MyFunctionalInterface는 추상 메서드가 하나만 있기 때문에 함수형 인터페이스입니다. @FunctionalInterface 어노테이션이 있기 때문에 컴파일러는 이 인터페이스가 함수형 인터페이스의 규칙을 따르는지 확인합니다.
함수형 인터페이스를 람다 표현식으로 간편하게 구현할 수 있어, 함수형 프로그래밍의 기본적인 단위로 활용됩니다.
내부적으로 클래스 생성: 익명 객체와 람다 표현식은 모두 내부적으로 새로운 클래스를 생성하여 사용합니다.
인터페이스의 구현 또는 추상 클래스의 확장: 둘 다 주로 인터페이스를 익명으로 구현하거나 추상 클래스를 익명으로 확장할 때 사용됩니다.
두 방식 모두 명시적으로 클래스를 선언하지 않지만 결국 구현 or 확장된 객체를 생성하게 됨
그러므로 자바 컴파일을 거친 class파일의 bytecode를 확인해보면 새로운 class가 구현되었음을 확인할 수 있음.
문법적 차이: 람다 표현식은 더 간결한 문법을 가지며, 특히 함수형 인터페이스의 경우에 유용합니다.
포용하는 개념: 익명 객체는 더 일반적인 상황에서 사용될 수 있으며, 람다 표현식은 주로 함수형 프로그래밍 스타일에서 사용됩니다.
변수의 final 여부: 람다 표현식은 외부의 변수를 암묵적으로 final로 처리하며, 이는 익명 객체와는 다릅니다.
둘 다 자바의 익명 클래스와 람다 표현식은 내부적으로는 클래스를 생성하여 사용하는 개념이지만, 문법적이고 사용하는 의도에서 차이가 있습니다.
+++
Java에서는 함수형 프로그래밍을 지원하기 위해 여러 내장 함수형 인터페이스를 제공합니다. 이러한 인터페이스들은 java.util.function 패키지에 속해 있습니다. 각각의 함수형 인터페이스는 특정한 종류의 함수를 표현하기 위해 설계되어 있습니다.
여기 몇 가지 주요한 내장 함수형 인터페이스들과 간단한 설명이 있습니다:
- Consumer
설명: 하나의 인자를 받아서 어떤 동작을 수행하는 함수형 인터페이스입니다.
메서드: void accept(T t)- Supplier
설명: 어떤 값을 제공하는 함수형 인터페이스입니다.
메서드: T get()- Function<T, R>
설명: 하나의 인자를 받아서 다른 타입으로 변환하는 함수형 인터페이스입니다.
메서드: R apply(T t)- Predicate
설명: 주어진 조건을 만족하는지 여부를 검사하는 함수형 인터페이스입니다.
메서드: boolean test(T t)- UnaryOperator
설명: 하나의 인자를 받아서 동일한 타입으로 반환하는 함수형 인터페이스입니다. (입력과 출력 타입이 동일)
메서드: T apply(T t)- BinaryOperator
설명: 두 개의 인자를 받아서 동일한 타입으로 반환하는 함수형 인터페이스입니다. (입력과 출력 타입이 동일)
메서드: T apply(T t1, T t2)- BiFunction<T, U, R>
설명: 두 개의 인자를 받아서 다른 타입으로 변환하는 함수형 인터페이스입니다.
메서드: R apply(T t, U u)- Runnable
설명: 어떤 동작을 수행하지만 인자나 반환 값이 없는 함수형 인터페이스입니다.
메서드: void run()- BiConsumer<T, U>
설명: 두 개의 인자를 받아서 어떤 동작을 수행하는 함수형 인터페이스입니다.
메서드: void accept(T t, U u)
이러한 함수형 인터페이스들은 람다 표현식을 통해 간편하게 사용할 수 있고, 함수형 프로그래밍 스타일의 코드 작성을 지원합니다. Java 8부터 추가된 이러한 기능은 컬렉션 처리, 스트림 API 등 다양한 곳에서 유용하게 활용됩니다.