모르지 않다는 것은 아는것과 다르다.

Java

LazyEvaluation,Curry,IntStream

채마스 2022. 3. 6. 23:17

Lazy Evaluation

  • Lambda의 계산은 그 결과값이 필요할 때가 되어서야 계산된다.
  • 이를 이용하여 불필요한 계산을 줄이거나 해당 코드의 실행 순서를 Lazy Evaluation 의도적으로 미룰 수 있다.
public class LazyEvaluation {

    public static void main(String[] args) {

        // 경우 1.
        if (or(returnTrue(), returnFalse())) {
            System.out.println("true");
        }

        // 경우 2. 
        if (lazyOr(() -> returnTrue(), () -> returnFalse())) {
            System.out.println("true");
        }

    }

    public static boolean or(boolean x, boolean y) {
        return x || y;
    }

    // Lazy Evaluation
    public static boolean lazyOr(Supplier<Boolean> x, Supplier<Boolean> y) {
        return x.get() || y.get();
    }

    public static boolean returnTrue() {
        System.out.println("Returning true");
        return true;
    }

    public static boolean returnFalse() {
        System.out.println("Returning false");
        return false;
    }
}
  • 위의 코드에서 경우 1 과 경우 2의 차이는 뭘까?
  • 경우 1은 반환값이 true, Returning true, Returning false 가 나온다. -> 그 이유는 returnTrue(), returnFalse() 메소드를 모두 호출하기 때문이다. -> 최적화 되지 못했다.
  • 반면 경우 2의 경우에는 returnTrue() 만 호출 되었다. -> returnTrue() 이미 true 를 반환하기 때문에 굳이 returnFalse() 메소드를 호출할 필요가 없는 것이다.
  • 이게 가능한 이유는 매개변수의 타입이 Supplier 이기 때문에 get() 메소드를 호출하기 전까지는 실행되지 않기 때문이다.

 

Stream 에서의 Lazy Evaluation

  • Stream 에서도 Lazy Evaluation 이 적용되어 있다.
Stream<Integer> integerStream = Stream.of(3, -2, 5, 8, -3, 10)
        .filter(x -> x > 0)
        .peek(x -> System.out.println("peeking " + x))
        .filter(x -> x % 2 ==0);
System.out.println("Before collect");

List<Integer> integers = integerStream.collect(Collectors.toList());
System.out.println("After collect: " + integers);
  • 코드만 보면 peek 메소드 내부에서 값을 출력한 뒤 "Before collect" 가 출력될 것 같지만 그렇지않다.
  • "Before collect" 가 먼저 출력되고 peek 메소드 내부에 있는 출력문이 출력된다.
  • 그 이유는 integerStream.collect(Collectors.toList()) 가 호출돼서 peek 이 사용되야겠다고 판단하기 때문이다. -> 결론은 stream 내부에 실행되는 행위가 최대한 뒤로 미뤄지는 것을 확인할 수 있다.

 

Curry

여러개의매개변수를받는함수를중첩된여러개의함수로쪼개어 매개변수를한번에받지않고여러단계에걸쳐나눠받을수있게 하는 기술이다.

BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
  • 위의 코드를 아래와 같이 바꿀 수 있다.
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;

 

IntStream

  • stream.forEach 만을 사용하면 index 값을 사용하기 어렵다.
  • 이렇때 IntStream 으로 해결할 수 있다.
IntStream.range(0, users.size()).forEach(i -> {
    User user = users.get(i);
    System.out.println("Do an operation on user " + user.getName() + " at index " + i);
});




REFERENCES

  • 이승환님의 JAVA Stream

'Java' 카테고리의 다른 글

Method Reference  (0) 2022.03.06
Collectors (JAVA STREAM)  (0) 2022.03.06
Stream 응용  (0) 2022.03.06
함수형 인터페이스  (0) 2022.02.26
제네릭  (0) 2022.02.26