Language/Java

[Java] ::new 는 무엇일까? Java 8 메소드 레퍼런스 (Method Reference)

마볼링 2023. 10. 31. 08:19

 

 

온라인 상의 자바 예시 코드를 보면 종종
Member::new 이런식으로 ::new 혹은 다른 메소드로 코드가 짜여진 경우가 있다

 

1. 메소드 레퍼런스

  • 람다 표현식을 구현할 때 쓸 수 있는 방법으로
    기존에 있던 다른 메소드를 참조하여 그 메소드 자체를 함수형 인터페이스의 구현체로 사용
  • 람다의 구현 자리를 기존에 이미 있는 어떤 메서드를 참조하는 방식
  • 람다 표현식이 단 하나의 메소드만을 호출하는 경우에 해당 람다 표현식에서
    불 필요한 매개변수를 제거하고 사용할 수 있다.
  • :: 연산자를 이용해 메소드 이름과 클래스를 분리하거나, 메소드 이름과 객체의 이름을 분리한다.
    • 클래스::메소드
    • 객체::메소드
    • 클래스::new

 

 

2. 유형

1) 스태틱 메소드 참조(Static Method Reference)

클래스::정적메소드 (static)
public class Calculator {
    public static int add(int a, int b) {
        return a + b;
    }
}
import java.util.function.BiFunction;

public class Main {
    public static void main(String[] args) {
        // BiFunction을 사용하여 두 정수를 더하는 연산을 정의
        BiFunction<Integer, Integer, Integer> addFunction = Calculator::add;

        // 정적 메서드 참조를 사용하여 add 메서드를 호출
        int result = addFunction.apply(3, 5);
        System.out.println("결과: " + result);
    }
}

 

BiFunction<T, U, R>

  • Java에서 함수형 프로그래밍을 지원하는 함수형 인터페이스(Functional Interface)중 하나
  • 함수형 인터페이스란 단 하나의 추상 메서드를 가지는 인터페이스로, 람다 표현식이나 메소드 참조와 같은
    함수형 프로그래밍 기법을 사용하기 위해 활용된다.
  • 두 개의 입력 인수를 받아들이고, 결과를 받아들이고, 결과를 반환하는 함수 표현
@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}
  • T 는 첫 번째 인수의 타입을 나타낸다
  • U 는 두 번째 인수의 타입을 나타낸다
  • R 은 결과 값의 타입을 나타낸다

 

2) 특정 객체의 인스턴스 메소드 참조(Instance Method Reference)

객체::인스턴스메소드 (public)
public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void sayHello() {
        System.out.println("안녕하세요, 제 이름은 " + name + "입니다.");
    }
}
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice");

        // Consumer를 사용하여 sayHello 메서드를 참조
        Consumer<Person> sayHelloConsumer = Person::sayHello;

        // 인스턴스 메서드 참조를 사용하여 sayHello 메서드를 호출
        sayHelloConsumer.accept(person);
    }
}

 

Consumer<T>

  • Java에서 함수형 프로그래밍을 지원하는 함수형 인터페이스(Functional Interface)중 하나
  • 입력값을 받아서 어떤 작업을 수행하지만, 결과값은 반환하는 않은 경우에 사용
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
  • T 는 입력값의 타입을 나타낸다

 

3) 생성자 참조(Constructor Method Reference)

클래스::new
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void introduce() {
        System.out.println("안녕하세요, 제 이름은 " + name + "이고, 나이는 " + age + "세 입니다.");
    }
}
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        // Function을 사용하여 생성자 메서드를 참조
        Function<String, Person> personConstructor = Person::new;

        // 생성자 메서드 참조를 사용하여 Person 객체를 생성
        Person person = personConstructor.apply("Alice");

        // 생성된 객체를 사용
        person.introduce();
    }
}

 

Function<T, R>

  • Java에서 함수형 프로그래밍을 지원하는 함수형 인터페이스(Functional Interface)중 하나
  • 하나의 입력을 받아서 결과를 반환하는 함수
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
  • T 는 입력값의 타입을 나타낸다
  • R  결과값의 타입을 나타낸다

 

2. 'Person::new ' vs 'new Person()' ?

참조 vs 직접 생성

위의 예시에서

Function<String, Person> personConstructor = Person::new

 

-> Person 클래스의 생성자를 참조하고, apply 메서드를 호출하면 Person 객체가 생성된다.

 

new Person사용시에는

Person person = new Person("Alice");

-> Person 객체를 직접 생성한다.

 

즉, 'Person::new'를 사용하면 필요한 시점에 'apply' 메서드를 호출하여 객체를 생성할 수 있고, 다른 매개변수를 받는 생성자를 참조하여 다양한 생성자를 호출할 수 있으며, 재상용이 가능하다.