Merge remote-tracking branch 'origin/PR-7308' into PR-7308
This commit is contained in:
@@ -45,7 +45,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source.version>11</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>11</maven.compiler.target.version>
|
||||
<jackson.version>2.14.1</jackson.version>
|
||||
<jackson.version>2.16.0</jackson.version>
|
||||
<gson.version>2.10</gson.version>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -21,8 +21,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -13,8 +13,4 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -26,8 +26,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -3,19 +3,34 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-20</artifactId>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>core-java-20</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>20</maven.compiler.source>
|
||||
<maven.compiler.target>20</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.24.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -41,25 +56,10 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.24.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>5.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<maven.compiler.source>20</maven.compiler.source>
|
||||
<maven.compiler.target>20</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -11,3 +11,4 @@ This module contains articles about arrays conversion in Java
|
||||
- [Converting an int[] to HashSet in Java](https://www.baeldung.com/java-converting-int-array-to-hashset)
|
||||
- [Convert an ArrayList of String to a String Array in Java](https://www.baeldung.com/java-convert-string-arraylist-array)
|
||||
- [Convert Char Array to Int Array in Java](https://www.baeldung.com/java-convert-char-int-array)
|
||||
- [How to Convert Byte Array to Char Array](https://www.baeldung.com/java-convert-byte-array-char)
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
<properties>
|
||||
<vavr.version>0.10.3</vavr.version>
|
||||
<java.version>11</java.version>
|
||||
<modelmapper.version>3.2.0</modelmapper.version>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -39,7 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.26</version>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -67,7 +67,7 @@
|
||||
<jmh.version>1.21</jmh.version>
|
||||
<commons-lang.version>2.2</commons-lang.version>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<jackson.version>2.15.2</jackson.version>
|
||||
<jackson.version>2.16.0</jackson.version>
|
||||
<org.json.version>20230618</org.json.version>
|
||||
</properties>
|
||||
</project>
|
||||
@@ -13,14 +13,11 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<spring.version>5.2.5.RELEASE</spring.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.13.1</version>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
@@ -51,4 +48,8 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.version>5.2.5.RELEASE</spring.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -4,5 +4,7 @@
|
||||
- [How to Write Hashmap to CSV File](https://www.baeldung.com/java-write-hashmap-csv)
|
||||
- [How to Get First or Last Entry From a LinkedHashMap in Java](https://www.baeldung.com/java-linkedhashmap-first-last-key-value-pair)
|
||||
- [How to Write and Read a File with a Java HashMap](https://www.baeldung.com/java-hashmap-write-read-file)
|
||||
- [Limiting the Max Size of a HashMap in Java](https://www.baeldung.com/java-hashmap-max-size)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-6)
|
||||
- [Limiting the Max Size of a HashMap in Java](https://www.baeldung.com/java-hashmap-size-bound)
|
||||
- [How to Sort LinkedHashMap By Values in Java](https://www.baeldung.com/java-sort-linkedhashmap-using-values)
|
||||
- [How to Increment a Map Value in Java](https://www.baeldung.com/java-increment-map-value)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-maps-6)
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-collections-maps-7</artifactId>
|
||||
<name>core-java-collections-maps-7</name>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<csv.version>1.5</csv.version>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
@@ -63,4 +59,10 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<csv.version>1.5</csv.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
package com.baeldung.concurrent.completablefuture;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CompletableFutureUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenAsyncTask_whenProcessingAsyncSucceed_thenReturnSuccess() throws ExecutionException, InterruptedException {
|
||||
Microservice mockMicroserviceA = mock(Microservice.class);
|
||||
Microservice mockMicroserviceB = mock(Microservice.class);
|
||||
|
||||
when(mockMicroserviceA.retrieveAsync(any())).thenReturn(CompletableFuture.completedFuture("Hello"));
|
||||
when(mockMicroserviceB.retrieveAsync(any())).thenReturn(CompletableFuture.completedFuture("World"));
|
||||
|
||||
CompletableFuture<String> resultFuture = processAsync(List.of(mockMicroserviceA, mockMicroserviceB));
|
||||
|
||||
String result = resultFuture.get();
|
||||
assertEquals("HelloWorld", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAsyncTask_whenProcessingAsyncWithException_thenReturnException() throws ExecutionException, InterruptedException {
|
||||
Microservice mockMicroserviceA = mock(Microservice.class);
|
||||
Microservice mockMicroserviceB = mock(Microservice.class);
|
||||
|
||||
when(mockMicroserviceA.retrieveAsync(any())).thenReturn(CompletableFuture.completedFuture("Hello"));
|
||||
when(mockMicroserviceB.retrieveAsync(any())).thenReturn(CompletableFuture.failedFuture(new RuntimeException("Simulated Exception")));
|
||||
CompletableFuture<String> resultFuture = processAsync(List.of(mockMicroserviceA, mockMicroserviceB));
|
||||
// Use assertThrows to verify that the expected exception is thrown
|
||||
ExecutionException exception = assertThrows(ExecutionException.class, resultFuture::get);
|
||||
// Assert the exception message
|
||||
assertEquals("Simulated Exception", exception.getCause()
|
||||
.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAsyncTask_whenProcessingAsyncWithTimeout_thenHandleTimeoutException() throws ExecutionException, InterruptedException {
|
||||
Microservice mockMicroserviceA = mock(Microservice.class);
|
||||
Microservice mockMicroserviceB = mock(Microservice.class);
|
||||
Executor delayedExecutor = CompletableFuture.delayedExecutor(200, TimeUnit.MILLISECONDS);
|
||||
when(mockMicroserviceA.retrieveAsync(any())).thenReturn(CompletableFuture.supplyAsync(() -> "Hello", delayedExecutor));
|
||||
Executor delayedExecutor2 = CompletableFuture.delayedExecutor(500, TimeUnit.MILLISECONDS);
|
||||
when(mockMicroserviceB.retrieveAsync(any())).thenReturn(CompletableFuture.supplyAsync(() -> "World", delayedExecutor2));
|
||||
CompletableFuture<String> resultFuture = processAsync(List.of(mockMicroserviceA, mockMicroserviceB));
|
||||
assertThrows(TimeoutException.class, () -> resultFuture.get(300, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompletableFuture_whenCompleted_thenStateIsDone() {
|
||||
Executor delayedExecutor = CompletableFuture.delayedExecutor(200, TimeUnit.MILLISECONDS);
|
||||
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello", delayedExecutor);
|
||||
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> " World");
|
||||
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> "!");
|
||||
CompletableFuture<String>[] cfs = new CompletableFuture[] { cf1, cf2, cf3 };
|
||||
|
||||
CompletableFuture<Void> allCf = CompletableFuture.allOf(cfs);
|
||||
|
||||
assertFalse(allCf.isDone());
|
||||
allCf.join();
|
||||
String result = Arrays.stream(cfs)
|
||||
.map(CompletableFuture::join)
|
||||
.collect(Collectors.joining());
|
||||
|
||||
assertFalse(allCf.isCancelled());
|
||||
assertTrue(allCf.isDone());
|
||||
assertFalse(allCf.isCompletedExceptionally());
|
||||
assertEquals(result, "Hello World!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompletableFuture_whenCompletedWithException_thenStateIsCompletedExceptionally() throws ExecutionException, InterruptedException {
|
||||
Executor delayedExecutor = CompletableFuture.delayedExecutor(200, TimeUnit.MILLISECONDS);
|
||||
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello", delayedExecutor);
|
||||
CompletableFuture<String> cf2 = CompletableFuture.failedFuture(new RuntimeException("Simulated Exception"));
|
||||
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> "!");
|
||||
CompletableFuture<String>[] cfs = new CompletableFuture[] { cf1, cf2, cf3 };
|
||||
|
||||
CompletableFuture<Void> allCf = CompletableFuture.allOf(cfs);
|
||||
|
||||
assertFalse(allCf.isDone());
|
||||
assertFalse(allCf.isCompletedExceptionally());
|
||||
|
||||
// Exception is expected, assert the cause
|
||||
CompletionException exception = assertThrows(CompletionException.class, allCf::join);
|
||||
|
||||
assertEquals("Simulated Exception", exception.getCause()
|
||||
.getMessage());
|
||||
assertTrue(allCf.isCompletedExceptionally());
|
||||
assertTrue(allCf.isDone());
|
||||
assertFalse(allCf.isCancelled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCompletableFuture_whenCancelled_thenStateIsCancelled() throws ExecutionException, InterruptedException {
|
||||
Executor delayedExecutor = CompletableFuture.delayedExecutor(200, TimeUnit.MILLISECONDS);
|
||||
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello", delayedExecutor);
|
||||
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> " World");
|
||||
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> "!");
|
||||
CompletableFuture<String>[] cfs = new CompletableFuture[] { cf1, cf2, cf3 };
|
||||
CompletableFuture<Void> allCf = CompletableFuture.allOf(cfs);
|
||||
assertFalse(allCf.isDone());
|
||||
assertFalse(allCf.isCompletedExceptionally());
|
||||
allCf.cancel(true);
|
||||
assertTrue(allCf.isCancelled());
|
||||
assertTrue(allCf.isDone());
|
||||
}
|
||||
|
||||
CompletableFuture<String> processAsync(List<Microservice> microservices) {
|
||||
List<CompletableFuture<String>> dataFetchFutures = fetchDataAsync(microservices);
|
||||
return combineResults(dataFetchFutures);
|
||||
}
|
||||
|
||||
private List<CompletableFuture<String>> fetchDataAsync(List<Microservice> microservices) {
|
||||
return microservices.stream()
|
||||
.map(client -> client.retrieveAsync(""))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private CompletableFuture<String> combineResults(List<CompletableFuture<String>> dataFetchFutures) {
|
||||
return CompletableFuture.allOf(dataFetchFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply(v -> dataFetchFutures.stream()
|
||||
.map(future -> future.exceptionally(ex -> {
|
||||
throw new CompletionException(ex);
|
||||
})
|
||||
.join())
|
||||
.collect(Collectors.joining()));
|
||||
}
|
||||
|
||||
interface Microservice {
|
||||
CompletableFuture<String> retrieveAsync(String input);
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,4 @@ This module contains articles about converting between Java date and time object
|
||||
- [Conversion From 12-Hour Time to 24-Hour Time in Java](https://www.baeldung.com/java-convert-time-format)
|
||||
- [Convert Epoch Time to LocalDate and LocalDateTime](https://www.baeldung.com/java-convert-epoch-localdate)
|
||||
- [Convert Timestamp String to Long in Java](https://www.baeldung.com/java-convert-timestamp-string-long)
|
||||
- [Convert Long Timestamp to LocalDateTime in Java](https://www.baeldung.com/java-convert-long-timestamp-localdatetime)
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LambdaSupplier<T> {
|
||||
|
||||
protected final Supplier<T> expensiveData;
|
||||
|
||||
public LambdaSupplier(Supplier<T> expensiveData) {
|
||||
this.expensiveData = expensiveData;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return expensiveData.get();
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyLambdaSupplier<T> extends LambdaSupplier<T> {
|
||||
|
||||
private T data;
|
||||
|
||||
public LazyLambdaSupplier(Supplier<T> expensiveData) {
|
||||
super(expensiveData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getData() {
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
return data = expensiveData.get();
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyLambdaThreadSafeSupplier<T> extends LambdaSupplier<T> {
|
||||
|
||||
private final AtomicReference<T> data;
|
||||
|
||||
public LazyLambdaThreadSafeSupplier(Supplier<T> expensiveData) {
|
||||
super(expensiveData);
|
||||
data = new AtomicReference<>();
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
if (data.get() == null) {
|
||||
synchronized (data) {
|
||||
if (data.get() == null) {
|
||||
data.set(expensiveData.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class LambdaSupplierUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenCalledMultipleTimes_thenShouldBeCalledMultipleTimes() {
|
||||
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
|
||||
Mockito.when(mockedExpensiveFunction.get())
|
||||
.thenReturn("expensive call");
|
||||
LambdaSupplier<String> testee = new LambdaSupplier<>(mockedExpensiveFunction);
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.never())
|
||||
.get();
|
||||
testee.getData();
|
||||
testee.getData();
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.times(2))
|
||||
.get();
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
public class LazyLambdaSupplierUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenCalledMultipleTimes_thenShouldBeCalledOnlyOnce() {
|
||||
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
|
||||
Mockito.when(mockedExpensiveFunction.get())
|
||||
.thenReturn("expensive call");
|
||||
LazyLambdaSupplier<String> testee = new LazyLambdaSupplier<>(mockedExpensiveFunction);
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.never())
|
||||
.get();
|
||||
testee.getData();
|
||||
testee.getData();
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
|
||||
.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledMultipleTimesConcurrently_thenShouldBeCalledMultipleTimes() throws InterruptedException {
|
||||
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
|
||||
Mockito.when(mockedExpensiveFunction.get())
|
||||
.thenAnswer((Answer<String>) invocation -> {
|
||||
Thread.sleep(1000L);
|
||||
return "Late response!";
|
||||
});
|
||||
LazyLambdaSupplier<String> testee = new LazyLambdaSupplier<>(mockedExpensiveFunction);
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.never())
|
||||
.get();
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||
executorService.invokeAll(List.of(testee::getData, testee::getData));
|
||||
executorService.shutdown();
|
||||
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.times(2))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.lazylambda;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
public class LazyLambdaThreadSafeSupplierUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenCalledMultipleTimes_thenShouldBeCalledOnlyOnce() {
|
||||
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
|
||||
Mockito.when(mockedExpensiveFunction.get())
|
||||
.thenReturn("expensive call");
|
||||
LazyLambdaThreadSafeSupplier<String> testee = new LazyLambdaThreadSafeSupplier<>(mockedExpensiveFunction);
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.never())
|
||||
.get();
|
||||
testee.getData();
|
||||
testee.getData();
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
|
||||
.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCalledMultipleTimesConcurrently_thenShouldBeCalledOnlyOnce() throws InterruptedException {
|
||||
@SuppressWarnings("unchecked") Supplier<String> mockedExpensiveFunction = Mockito.mock(Supplier.class);
|
||||
Mockito.when(mockedExpensiveFunction.get())
|
||||
.thenAnswer((Answer<String>) invocation -> {
|
||||
Thread.sleep(1000L);
|
||||
return "Late response!";
|
||||
});
|
||||
LazyLambdaThreadSafeSupplier<String> testee = new LazyLambdaThreadSafeSupplier<>(mockedExpensiveFunction);
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.never())
|
||||
.get();
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(4);
|
||||
executorService.invokeAll(List.of(testee::getData, testee::getData));
|
||||
executorService.shutdown();
|
||||
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
|
||||
Mockito.verify(mockedExpensiveFunction, Mockito.times(1))
|
||||
.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,3 +9,5 @@ This module contains articles about core features in the Java language
|
||||
- [Get a Random Element From a Set in Java](https://www.baeldung.com/java-set-draw-sample)
|
||||
- [Stop Executing Further Code in Java](https://www.baeldung.com/java-stop-running-code)
|
||||
- [Using the Apache Commons Lang 3 for Comparing Objects in Java](https://www.baeldung.com/java-apache-commons-lang-3-compare-objects)
|
||||
- [Return First Non-null Value in Java](https://www.baeldung.com/java-first-non-null)
|
||||
- [Static Final Variables in Java](https://www.baeldung.com/java-static-final-variables)
|
||||
|
||||
@@ -23,6 +23,16 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -39,6 +49,11 @@
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>${mapstruct.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>${jmh.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -50,6 +65,7 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mapstruct.version>1.6.0.Beta1</mapstruct.version>
|
||||
<jmh.version>1.37</jmh.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.staticfinal;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Bike {
|
||||
public static final int TIRE = 2;
|
||||
public static final int PEDAL;
|
||||
public static final HashMap<String, Integer> PART = new HashMap<>();
|
||||
|
||||
static {
|
||||
PEDAL = 5;
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.recursivelysumintarray;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class RecursivelySumIntArrayUnitTest {
|
||||
|
||||
private static final int[] INT_ARRAY = { 1, 2, 3, 4, 5 };
|
||||
|
||||
static int sumIntArray1(int[] array) {
|
||||
if (array.length == 1) {
|
||||
return array[0];
|
||||
} else {
|
||||
return array[0] + sumIntArray1(Arrays.copyOfRange(array, 1, array.length));
|
||||
}
|
||||
}
|
||||
|
||||
static int sumIntArray2(int[] array, int index) {
|
||||
if (index == 0) {
|
||||
return array[index];
|
||||
} else {
|
||||
return array[index] + sumIntArray2(array, index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingSumIntArray1_thenGetExpectedResult() {
|
||||
assertEquals(15, sumIntArray1(INT_ARRAY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingSumIntArray2_thenGetExpectedResult() {
|
||||
assertEquals(15, sumIntArray2(INT_ARRAY, INT_ARRAY.length - 1));
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.baeldung.recursivelysumintarray;
|
||||
|
||||
import static com.baeldung.recursivelysumintarray.RecursivelySumIntArrayUnitTest.sumIntArray1;
|
||||
import static com.baeldung.recursivelysumintarray.RecursivelySumIntArrayUnitTest.sumIntArray2;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@State(Scope.Thread)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Warmup(iterations = 2)
|
||||
@Fork(1)
|
||||
@Measurement(iterations = 5)
|
||||
public class SumArrayBenchmark {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Options options = new OptionsBuilder().include(SumArrayBenchmark.class.getSimpleName())
|
||||
.build();
|
||||
new Runner(options).run();
|
||||
}
|
||||
|
||||
@Param({ "10", "10000" })
|
||||
public int size;
|
||||
int[] array;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
var r = new Random();
|
||||
array = new int[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
array[i] = r.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int withArrayCopy() {
|
||||
return sumIntArray1(array);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int withoutArrayCopy() {
|
||||
return sumIntArray2(array, array.length - 1);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.staticfinal;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class BikeUnitTest {
|
||||
|
||||
@Test
|
||||
void givenTireConstantSetUponDeclaration_whenGetTire_thenReturnTwo() {
|
||||
assertEquals(2, Bike.TIRE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenPedalConstantSetByStaticBlock_whenGetPedal_thenReturnFive() {
|
||||
assertEquals(5, Bike.PEDAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenPartConstantObject_whenObjectStateChanged_thenCorrect() {
|
||||
Bike.PART.put("seat", 1);
|
||||
assertEquals(1, Bike.PART.get("seat"));
|
||||
|
||||
Bike.PART.put("seat", 5);
|
||||
assertEquals(5, Bike.PART.get("seat"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMathClass_whenAccessingPiConstant_thenVerifyPiValueIsCorrect() {
|
||||
assertEquals(3.141592653589793, Math.PI);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,3 +10,4 @@ This module contains articles about Java operators
|
||||
- [Check if at Least Two Out of Three Booleans Are True in Java](https://www.baeldung.com/java-check-two-of-three-booleans)
|
||||
- [Alternatives for instanceof Operator in Java](https://www.baeldung.com/java-instanceof-alternatives)
|
||||
- [What Does “––>” Mean in Java?](https://www.baeldung.com/java-minus-minus-greaterthan)
|
||||
- [All the Ways Java Uses the Colon Character](https://www.baeldung.com/java-colon)
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package com.baeldung.colonexamples;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Examples of the different ways Java uses the colon (:) character.
|
||||
*/
|
||||
public class ColonExamples {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(ColonExamples.class);
|
||||
|
||||
public void example1_enhancedForLoop() {
|
||||
|
||||
// Original style
|
||||
for(int i = 0; i < 10; i++) {
|
||||
// do something
|
||||
}
|
||||
|
||||
// Using enhanced for loop
|
||||
int[] numbers = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
for(int i : numbers) {
|
||||
// do something
|
||||
}
|
||||
|
||||
// Using List instead of array
|
||||
List<Integer> numbersList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
for(Integer i : numbersList) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
|
||||
public void example2_switchStatement(String animal) {
|
||||
|
||||
// Original style
|
||||
if(animal.equals("cat")) {
|
||||
System.out.println("meow");
|
||||
}
|
||||
else if(animal.equals("lion")) {
|
||||
System.out.println("roar");
|
||||
}
|
||||
else if(animal.equals("dog") || animal.equals("seal")) {
|
||||
System.out.println("bark");
|
||||
}
|
||||
else {
|
||||
System.out.println("unknown");
|
||||
}
|
||||
|
||||
// Using switch statement
|
||||
switch(animal) {
|
||||
case "cat":
|
||||
System.out.println("meow");
|
||||
break;
|
||||
case "lion":
|
||||
System.out.println("roar");
|
||||
break;
|
||||
case "dog":
|
||||
case "seal":
|
||||
System.out.println("bark");
|
||||
break;
|
||||
default:
|
||||
System.out.println("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
public void example3_labels() {
|
||||
|
||||
// For loops without labels
|
||||
for(int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
if (checkSomeCondition()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outterLoop: for(int i = 0; i < 10; i++) {
|
||||
innerLoop: for (int j = 0; j < 10; j++) {
|
||||
if (checkSomeCondition()) {
|
||||
break outterLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void example4_ternaryOperator() {
|
||||
|
||||
// Original way using if/else
|
||||
int x;
|
||||
if(checkSomeCondition()) {
|
||||
x = 1;
|
||||
}
|
||||
else {
|
||||
x = 2;
|
||||
}
|
||||
|
||||
// Using ternary operator
|
||||
x = checkSomeCondition() ? 1 : 2;
|
||||
|
||||
// Using with other statements
|
||||
boolean remoteCallResult = callRemoteApi();
|
||||
LOG.info(String.format(
|
||||
"The result of the remote API call %s successful",
|
||||
remoteCallResult ? "was" : "was not"
|
||||
));
|
||||
}
|
||||
|
||||
public void example5_methodReferences() {
|
||||
// Original way without lambdas and method references
|
||||
List<String> names = Arrays.asList("ross", "joey", "chandler");
|
||||
List<String> upperCaseNames = new ArrayList<>();
|
||||
for(String name : names) {
|
||||
upperCaseNames.add(name.toUpperCase());
|
||||
}
|
||||
|
||||
// Using method reference with stream map operation
|
||||
List<String> petNames = Arrays.asList("ross", "joey", "chandler");
|
||||
List<String> petUpperCaseNames = petNames
|
||||
.stream()
|
||||
.map(String::toUpperCase)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Method reference with stream filter
|
||||
List<Animal> pets = Arrays.asList(new Cat(), new Dog(), new Parrot());
|
||||
List<Animal> onlyDogs = pets
|
||||
.stream()
|
||||
.filter(Dog.class::isInstance)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Method reference with constructors
|
||||
Set<Animal> onlyDogsSet = pets
|
||||
.stream()
|
||||
.filter(Dog.class::isInstance)
|
||||
.collect(Collectors.toCollection(TreeSet::new));
|
||||
}
|
||||
|
||||
public void example6_asserttion() {
|
||||
// Original way without assertions
|
||||
Connection conn = getConnection();
|
||||
if(conn == null) {
|
||||
throw new RuntimeException("Connection is null");
|
||||
}
|
||||
|
||||
// Using assert keyword
|
||||
assert getConnection() != null : "Connection is null";
|
||||
}
|
||||
|
||||
private boolean checkSomeCondition() {
|
||||
return new Random().nextBoolean();
|
||||
}
|
||||
|
||||
private boolean callRemoteApi() {
|
||||
return new Random().nextBoolean();
|
||||
}
|
||||
|
||||
private Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static interface Animal {
|
||||
|
||||
}
|
||||
private static class Dog implements Animal {
|
||||
|
||||
}
|
||||
|
||||
private static class Cat implements Animal {
|
||||
|
||||
}
|
||||
|
||||
private static class Parrot implements Animal {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
## Relevant Articles
|
||||
- [Check if a double Is an Integer in Java](https://www.baeldung.com/java-check-double-integer)
|
||||
@@ -0,0 +1,37 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-numbers-7</artifactId>
|
||||
<name>core-java-numbers-7</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>core-java-numbers-7</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user