Skip to content

Commit 784cb23

Browse files
Merge pull request #15219 from maenolis/BAEL-7014
BAEL 7014
2 parents 7f894fe + 9a003c4 commit 784cb23

File tree

6 files changed

+190
-0
lines changed

6 files changed

+190
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.function.Supplier;
4+
5+
public class LambdaSupplier<T> {
6+
7+
protected final Supplier<T> expensiveData;
8+
9+
public LambdaSupplier(Supplier<T> expensiveData) {
10+
this.expensiveData = expensiveData;
11+
}
12+
13+
public T getData() {
14+
return expensiveData.get();
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.function.Supplier;
4+
5+
public class LazyLambdaSupplier<T> extends LambdaSupplier<T> {
6+
7+
private T data;
8+
9+
public LazyLambdaSupplier(Supplier<T> expensiveData) {
10+
super(expensiveData);
11+
}
12+
13+
@Override
14+
public T getData() {
15+
if (data != null) {
16+
return data;
17+
}
18+
return data = expensiveData.get();
19+
}
20+
21+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.concurrent.atomic.AtomicReference;
4+
import java.util.function.Supplier;
5+
6+
public class LazyLambdaThreadSafeSupplier<T> extends LambdaSupplier<T> {
7+
8+
private final AtomicReference<T> data;
9+
10+
public LazyLambdaThreadSafeSupplier(Supplier<T> expensiveData) {
11+
super(expensiveData);
12+
data = new AtomicReference<>();
13+
}
14+
15+
public T getData() {
16+
if (data.get() == null) {
17+
synchronized (data) {
18+
if (data.get() == null) {
19+
data.set(expensiveData.get());
20+
}
21+
}
22+
}
23+
return data.get();
24+
}
25+
26+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.function.Supplier;
4+
5+
import org.junit.Test;
6+
import org.mockito.Mockito;
7+
8+
public class LambdaSupplierUnitTest {
9+
10+
@Test
11+
public void whenCalledMultipleTimes_thenShouldBeCalledMultipleTimes() {
12+
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
13+
Mockito.when(mockedExpensiveFunction.get())
14+
.thenReturn("expensive call");
15+
LambdaSupplier<String> testee = new LambdaSupplier<>(mockedExpensiveFunction);
16+
Mockito.verify(mockedExpensiveFunction, Mockito.never())
17+
.get();
18+
testee.getData();
19+
testee.getData();
20+
Mockito.verify(mockedExpensiveFunction, Mockito.times(2))
21+
.get();
22+
}
23+
24+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.List;
4+
import java.util.concurrent.ExecutorService;
5+
import java.util.concurrent.Executors;
6+
import java.util.concurrent.TimeUnit;
7+
import java.util.function.Supplier;
8+
9+
import org.junit.Test;
10+
import org.mockito.Mockito;
11+
import org.mockito.stubbing.Answer;
12+
13+
public class LazyLambdaSupplierUnitTest {
14+
15+
@Test
16+
public void whenCalledMultipleTimes_thenShouldBeCalledOnlyOnce() {
17+
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
18+
Mockito.when(mockedExpensiveFunction.get())
19+
.thenReturn("expensive call");
20+
LazyLambdaSupplier<String> testee = new LazyLambdaSupplier<>(mockedExpensiveFunction);
21+
Mockito.verify(mockedExpensiveFunction, Mockito.never())
22+
.get();
23+
testee.getData();
24+
testee.getData();
25+
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
26+
.get();
27+
}
28+
29+
@Test
30+
public void whenCalledMultipleTimesConcurrently_thenShouldBeCalledMultipleTimes() throws InterruptedException {
31+
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
32+
Mockito.when(mockedExpensiveFunction.get())
33+
.thenAnswer((Answer<String>) invocation -> {
34+
Thread.sleep(1000L);
35+
return "Late response!";
36+
});
37+
LazyLambdaSupplier<String> testee = new LazyLambdaSupplier<>(mockedExpensiveFunction);
38+
Mockito.verify(mockedExpensiveFunction, Mockito.never())
39+
.get();
40+
41+
ExecutorService executorService = Executors.newFixedThreadPool(4);
42+
executorService.invokeAll(List.of(testee::getData, testee::getData));
43+
executorService.shutdown();
44+
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
45+
executorService.shutdownNow();
46+
}
47+
48+
Mockito.verify(mockedExpensiveFunction, Mockito.times(2))
49+
.get();
50+
}
51+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.baeldung.lazylambda;
2+
3+
import java.util.List;
4+
import java.util.concurrent.ExecutorService;
5+
import java.util.concurrent.Executors;
6+
import java.util.concurrent.TimeUnit;
7+
import java.util.function.Supplier;
8+
9+
import org.junit.Test;
10+
import org.mockito.Mockito;
11+
import org.mockito.stubbing.Answer;
12+
13+
public class LazyLambdaThreadSafeSupplierUnitTest {
14+
15+
@Test
16+
public void whenCalledMultipleTimes_thenShouldBeCalledOnlyOnce() {
17+
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
18+
Mockito.when(mockedExpensiveFunction.get())
19+
.thenReturn("expensive call");
20+
LazyLambdaThreadSafeSupplier<String> testee = new LazyLambdaThreadSafeSupplier<>(mockedExpensiveFunction);
21+
Mockito.verify(mockedExpensiveFunction, Mockito.never())
22+
.get();
23+
testee.getData();
24+
testee.getData();
25+
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
26+
.get();
27+
}
28+
29+
@Test
30+
public void whenCalledMultipleTimesConcurrently_thenShouldBeCalledOnlyOnce() throws InterruptedException {
31+
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
32+
Mockito.when(mockedExpensiveFunction.get())
33+
.thenAnswer((Answer<String>) invocation -> {
34+
Thread.sleep(1000L);
35+
return "Late response!";
36+
});
37+
LazyLambdaThreadSafeSupplier<String> testee = new LazyLambdaThreadSafeSupplier<>(mockedExpensiveFunction);
38+
Mockito.verify(mockedExpensiveFunction, Mockito.never())
39+
.get();
40+
41+
ExecutorService executorService = Executors.newFixedThreadPool(4);
42+
executorService.invokeAll(List.of(testee::getData, testee::getData));
43+
executorService.shutdown();
44+
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
45+
executorService.shutdownNow();
46+
}
47+
48+
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
49+
.get();
50+
}
51+
52+
}

0 commit comments

Comments
 (0)