Java Lazy Evaluation이란?
Lazy Evaluation이란?
실제로 필요한 경우에만 연산을 시작하는 것을 의미합니다.
반대로 eager evaluation은 할당되자마자 연산을 시작합니다.
Java는 eager evaluation을 기본으로 하고 일부 Lazy Evaluation이 존재했습니다.
Java8이 나오면서 Java에서 Lazy Evauation을 좀 더 유연하게 사용할 수 있습니다.
Eagar Evaluation 예시
public class LazyEvaluation {
public static void main(String[] args) throws InterruptedException {
double start = System.currentTimeMillis();
printIfValid(0,expensiveMethod("junuuu"));
printIfValid(-1,expensiveMethod("junuuu"));
printIfValid(-2,expensiveMethod("junuuu"));
System.out.println("소요 시간 : " + (System.currentTimeMillis() - start) / 1000);
}
private static void printIfValid(int validValue, String printValue){
if(validValue >= 0){
System.out.println("The value is " + printValue);
} else{
System.out.println("Invalid");
}
}
private static String expensiveMethod(String value) throws InterruptedException {
Thread.sleep(3000);
return value;
}
}
위의 코드는 printIfValid 메서드가 3번 호출되고 이에 대한 소요시간을 측정하는 코드입니다.
printIfValid 메서드는 validValue, printValue를 인자로 받고 validValue의 값에 따라 두 번째 인자인 printValue를 사용하기도 하고 사용하지 않기도 합니다.
만약 -1, -2가 첫 번째 인자로 들어왔다면 printValue는 필요하지 않을 것이고 expensiveMethod가 호출되지 않는다면 훨씬 좋을 것입니다.
하지만 위의 결과는 다음과 같이 출력됩니다.
The value is junuuu
Invalid
Invalid
소요 시간 : 9.019
Java 7 이전의 Lazy Evaluation
조건문에 직접 명시하는 방법밖에 존재하지 않습니다.
이렇게 하면 결괏값을 변수로 받은 후 재활용이 안 되는 단점이 있습니다.
예를 들어 printIfValid 메서드가 다음과 같이 변해야 합니다.
private static void printIfValid(int validValue){
if(validValue >= 0){
System.out.println("The value is " + expensiveMethod("junuuu"));
} else{
System.out.println("Invalid");
}
}
이렇게 되면 else 구문에서는 expensiveMethod가 호출되지 않지만 변수로서 재활용도는 떨어지게 됩니다.
Java 8 이후의 Lazy Evaluation
import java.util.function.Supplier;
public class LazyEvaluation {
public static void main(String[] args) {
double start = System.currentTimeMillis();
Supplier<String> printValueSupplier = new Supplier<String>() {
@Override
public String get() {
return expensiveMethod("junuuu");
}
};
printIfValid(0, printValueSupplier);
printIfValid(-1, () -> expensiveMethod("junuuu"));
printIfValid(-2, () -> expensiveMethod("kim"));
System.out.println("소요 시간 : " + (System.currentTimeMillis() - start) / 1000);
}
private static void printIfValid(int validValue, Supplier<String> printValueSupplier) {
if (validValue >= 0) {
System.out.println("The value is " + printValueSupplier.get());
} else {
System.out.println("Invalid");
}
}
private static String expensiveMethod(String value) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
}
다양한 Funtional Interface들이 등장하게 되었고 그중 Supplier라는 함수가 있습니다.
Supplier는 이름을 통해서 유추할 수 있듯이 파라미터를 하나도 받지 않고 T라는 객체를 생성하는 함수입니다.
Supplier는 get 메서드를 통하여 값을 반환할 수 있습니다.
람다식이 익숙하지 않은 분들이 있을 수 있을 것 같아 익명 클래스로 한 번 표현하고 람다식으로 2번 표현해 보았습니다.
원래라면 바로 호출하던 것을 함수화시켜서 실제로 validValue가 0이 넘을 때만 get 메서드를 호출하면서 Lazy Evalutaion이 구현 가능해집니다.
Java 8 Stream과 Lazy Evaluation
Java 8 Stream에서는 Lazy Evaluation이 기본이 됩니다.
각 단계에 모든 원소에 대해서 연산을 하지 않고 필요한 부분만 연산을 처리합니다.
만약 List에 1~15까지의 수가 존재하고 여기서 처음 3개의 값을 뽑아내는 연산을 구현해 보겠습니다.
import java.util.ArrayList;
import java.util.List;
public class StreamLazyEvaluation {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
int count = 0;
List<Integer> result = new ArrayList<>();
for(Integer cur : numbers){
System.out.println("curNum : " + cur);
if(count++ < 3 ){
result.add(cur);
}
}
System.out.println(result);
}
}
위의 코드로 결과로는 다음과 같이 15번의 curNum이 출력됩니다.
curNum : 1
curNum : 2
curNum : 3
curNum : 4
curNum : 5
curNum : 6
curNum : 7
curNum : 8
curNum : 9
curNum : 10
curNum : 11
curNum : 12
curNum : 13
curNum : 14
curNum : 15
[1, 2, 3]
즉, Eager Evaluation입니다. 여기서 Stream을 도입해 보겠습니다.
Stream으로 1~15까지에서 처음 3개 수 뽑아내기
import java.util.List;
import java.util.stream.Collectors;
public class StreamLazyEvaluation {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
List<Integer> result = numbers.stream()
.peek(cur -> System.out.println("curNum : " + cur))
.limit(3)
.collect(Collectors.toList());
System.out.println(result);
}
}
1. List를 stream으로 변환합니다.
2. 중간중간 현재 수를 peek를 사용하여 출력합니다.
3. limit메서드로 결과를 최대 3개로 제한합니다.
4. collect메서드로 결과를 List로 바꿔줍니다.
위의 코드의 결과는 다음과 같습니다.
curNum : 1
curNum : 2
curNum : 3
[1, 2, 3]
코드도 엄청나게 간결해졌으며, Lazy Evaluation이 적용되었습니다.
출처
https://sabarada.tistory.com/153
[Java] Java와 Lazy Evaluation
Lazy evaluation은 실제로 필요로 해지는 경우에 연산을 시작하는 것입니다. 이 반대로는 eager evaluation이 있으며 이는 할당되자마다 연산을 시작합니다. 기본적인 Java의 기조는 eager evaluation을 기본으
sabarada.tistory.com
https://www.youtube.com/watch?v=7e7FCMFrwcg&list=PLRIMoAKN8c6O8_VHOyBOhzBCeN7ShyJ27&index=7
https://sabarada.tistory.com/154?category=815130
[java] Java와 Lazy evaluation - Java8 Stream
안녕하세요. 이전시간에 우리는 Lazy evaluation에 대해서 알아보는 시간을 가졌었습니다. 오늘은 이어서 Java8의 Stream의 Lazy Evaluation에 대해서 알아보는 시간을 가져보겠습니다. 우리는 이전 시간 [Ja
sabarada.tistory.com