자바 람다식, 함수형 인터페이스

21058 단어 JavaJava

제대로 좀 이해하고 쓰자. 람다식!
내가 안 익숙해서 그런지 장점인 가독성이 높아진다는 공감이 안된다..ㅎ..

자바 람다식, 함수형 인터페이스, 메소드 참조

참조
https://mangkyu.tistory.com/113
https://juyoung-1008.tistory.com/48
https://countryxide.tistory.com/127
https://imcts.github.io/java-method-reference/

람다식 (Lambda Expression)

  • 함수를 하나의 식으로 표현 한 것
  • 익명 함수의 한 종류
    * 함수를 변수처럼 선언해서 사용 하기 때문에 메소드의 이름이 불필요 함
// 기존
public String hello() {
	return "hello world!"
}

// 람다식
() -> "hello world!"
  • 람다식에서 사용되는 지역변수는 상수로 간주된다.
  • 람다식으로 선언된 변수명은 다른 변수명과 중복 될 수 없다.
  • 함수를 만드는 과정없이 한번에 처리할 수 있어 생산성이 높아진다.

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

  • 함수를 1급 객체처럼 다룰 수 있게 해줌으로써 함수를 변수처럼 선언 할 수 있게 됨.
  • @FunctionalInterface 어노테이션 : 인터페이스에 선언하여 단 하나의 추상 메소드만을 갖도록 제한함

Java 제공 함수형 인터페이스

1. Supplier

Supplier<T> : 매개변수 없이 반환값(T) 만을 가지는 함수형 인터페이스
메소드 : supplier.get()

@FunctionalInterface
  public interface Supplier<T> {
  	T get();
  }
  
  Supplier<String> supplier = () -> "hello word";
  System.out.println(supplier.get());

2. Consumer

Consumer<T> : 매개변수(T)를 받아서 사용하고 반환값은 없는 함수형 인터페이스
메소드 : consumer.accept(T);

@FunctionalInterface
public interface Consumer<T> {
	void accept(T t);
    default Consumer<T> andThen(Consumer<? super T>after) {
    	Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); }
    }
}

Consumer<String> consumer = (str) -> System.out.println(str.split(" ")[0]);
consumer.andThen(System.out::println).accept("hello world");

3. Function

Function<T, R> : 매개변수(T)를 받아서 반환값(R)을 가지는 함수형 인터페이스
메소드 : function.apply(T);

@FunctionalInterface
public interface Function<T, R> {
	R apply(T t);
    
    // compose
    // andThen
    // identity
}

Function<String, Integer> function = (str) -> str.length();
function.apply("hello world");

4. Predicate

Predicate<T> : 매개변수(T)를 받아 처리 한 후 Boolean 값을 반환하는 인터페이스

@FunctionalInterface
public interface Predicate<T> {
	boolean test(T t);
}

Predicate<String> predicate = (str) -> str.equals("hello world");
predicate.test("hello");

메소드 참조(Method Reference)

  • 메소드 참조를 통해 매개 변수의 정보 및 리턴 타입을 파악하여 람다식에서 불필요한 매개 변수를 제거하는 것을 의미한다.
// 기존 사용하고 있던 코드 
Car[] cars = new Car[] {"min", "choi", "test"};

List<Car> list = Arrays.asList(cars);
for (Car car : cars) 
	System.out.println(car);

단점: 반복적인 for문 사용

// forEach 적용
Car[] cars = new Car[] {"min", "choi", "test"};

List<Car> list = Arrays.asList(cars);
list.forEach(car -> System.out.println(car));

장점: 조금 더 간결하다.
단점: forEach의 매개변수로 함수형 인터페이스(Consumer)를 전달 받음.
사실 왜 단점인지 잘 모르겠다. 더 찾아 봐야 할 부분..

여튼 그래서 System 클래스가 가진 println 메소드를 forEach에게 전달하기 위해서 메소드 참조를 사용함.

// forEach 적용
Car[] cars = new Car[] {"min", "choi", "test"};

List<Car> list = Arrays.asList(cars);
list.forEach(System.out::println);

:: 연산자는 이름과 클래스를 분리하거나 메소드 이름과 객체의 이름을 분리함.

1. 클래스::인스턴스 메소드(public)

(x, y) -> x.compareToIgnoreCase(y);
String::compareToIgnoreCase 

2. 클래스::정적 메소드(static)

x -> object.isNull(x)
Object:isNull

3. 객체::인스턴스 메소드(new)

x -> System.out.println(x)
System.out::println
  • 생성자
// 클래스 생성
Car car = new Car();
Car minCar = new Car("min");
Car choiCar = new Car("min", "choi");

// 람다식 사용
Function<String, Car> minCar = (name) -> new Car(name);

// 메소드 참조 사용
Function<String, Car> minCar = Car::new

좋은 웹페이지 즐겨찾기