Merge remote-tracking branch 'upstream/master' into feature/BAEL-7062-GetIndex
This commit is contained in:
@@ -5,7 +5,6 @@ This module contains articles about Java 11 core features
|
||||
### Relevant articles
|
||||
- [Guide To Java 8 Optional](https://www.baeldung.com/java-optional)
|
||||
- [Guide to Java Reflection](http://www.baeldung.com/java-reflection)
|
||||
- [Guide to Java 8’s Collectors](https://www.baeldung.com/java-8-collectors)
|
||||
- [New Features in Java 11](https://www.baeldung.com/java-11-new-features)
|
||||
- [Getting the Java Version at Runtime](https://www.baeldung.com/get-java-version-runtime)
|
||||
- [Invoking a SOAP Web Service in Java](https://www.baeldung.com/java-soap-web-service)
|
||||
|
||||
-237
@@ -1,237 +0,0 @@
|
||||
package com.baeldung.collectors;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class Java8CollectorsUnitTest {
|
||||
|
||||
private final List<String> givenList = Arrays.asList("a", "bb", "ccc", "dd");
|
||||
private final List<String> listWithDuplicates = Arrays.asList("a", "bb", "c", "d", "bb");
|
||||
|
||||
@Test
|
||||
public void whenCollectingToList_shouldCollectToList() throws Exception {
|
||||
final List<String> result = givenList.stream().collect(toList());
|
||||
|
||||
assertThat(result).containsAll(givenList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToUnmodifiableList_shouldCollectToUnmodifiableList() {
|
||||
final List<String> result = givenList.stream().collect(toUnmodifiableList());
|
||||
|
||||
assertThatThrownBy(() -> result.add("foo"))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToSet_shouldCollectToSet() throws Exception {
|
||||
final Set<String> result = givenList.stream().collect(toSet());
|
||||
|
||||
assertThat(result).containsAll(givenList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToUnmodifiableSet_shouldCollectToUnmodifiableSet() {
|
||||
final Set<String> result = givenList.stream().collect(toUnmodifiableSet());
|
||||
|
||||
assertThatThrownBy(() -> result.add("foo"))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenContainsDuplicateElements_whenCollectingToSet_shouldAddDuplicateElementsOnlyOnce() throws Exception {
|
||||
final Set<String> result = listWithDuplicates.stream().collect(toSet());
|
||||
|
||||
assertThat(result).hasSize(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToCollection_shouldCollectToCollection() throws Exception {
|
||||
final List<String> result = givenList.stream().collect(toCollection(LinkedList::new));
|
||||
|
||||
assertThat(result).containsAll(givenList).isInstanceOf(LinkedList.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToImmutableCollection_shouldThrowException() throws Exception {
|
||||
assertThatThrownBy(() -> {
|
||||
givenList.stream().collect(toCollection(ImmutableList::of));
|
||||
}).isInstanceOf(UnsupportedOperationException.class);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToMap_shouldCollectToMap() throws Exception {
|
||||
final Map<String, Integer> result = givenList.stream().collect(toMap(Function.identity(), String::length));
|
||||
|
||||
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("ccc", 3).containsEntry("dd", 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToUnmodifiableMap_shouldCollectToUnmodifiableMap() {
|
||||
final Map<String, Integer> result = givenList.stream()
|
||||
.collect(toUnmodifiableMap(Function.identity(), String::length));
|
||||
|
||||
assertThatThrownBy(() -> result.put("foo", 3))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingToMapwWithDuplicates_shouldCollectToMapMergingTheIdenticalItems() throws Exception {
|
||||
final Map<String, Integer> result = listWithDuplicates.stream().collect(
|
||||
toMap(
|
||||
Function.identity(),
|
||||
String::length,
|
||||
(item, identicalItem) -> item
|
||||
)
|
||||
);
|
||||
|
||||
assertThat(result).containsEntry("a", 1).containsEntry("bb", 2).containsEntry("c", 1).containsEntry("d", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenContainsDuplicateElements_whenCollectingToMap_shouldThrowException() throws Exception {
|
||||
assertThatThrownBy(() -> {
|
||||
listWithDuplicates.stream().collect(toMap(Function.identity(), String::length));
|
||||
}).isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCollectingAndThen_shouldCollect() throws Exception {
|
||||
final List<String> result = givenList.stream().collect(collectingAndThen(toList(), ImmutableList::copyOf));
|
||||
|
||||
assertThat(result).containsAll(givenList).isInstanceOf(ImmutableList.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenJoining_shouldJoin() throws Exception {
|
||||
final String result = givenList.stream().collect(joining());
|
||||
|
||||
assertThat(result).isEqualTo("abbcccdd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenJoiningWithSeparator_shouldJoinWithSeparator() throws Exception {
|
||||
final String result = givenList.stream().collect(joining(" "));
|
||||
|
||||
assertThat(result).isEqualTo("a bb ccc dd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenJoiningWithSeparatorAndPrefixAndPostfix_shouldJoinWithSeparatorPrePost() throws Exception {
|
||||
final String result = givenList.stream().collect(joining(" ", "PRE-", "-POST"));
|
||||
|
||||
assertThat(result).isEqualTo("PRE-a bb ccc dd-POST");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPartitioningBy_shouldPartition() throws Exception {
|
||||
final Map<Boolean, List<String>> result = givenList.stream().collect(partitioningBy(s -> s.length() > 2));
|
||||
|
||||
assertThat(result).containsKeys(true, false).satisfies(booleanListMap -> {
|
||||
assertThat(booleanListMap.get(true)).contains("ccc");
|
||||
|
||||
assertThat(booleanListMap.get(false)).contains("a", "bb", "dd");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCounting_shouldCount() throws Exception {
|
||||
final Long result = givenList.stream().collect(counting());
|
||||
|
||||
assertThat(result).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSummarizing_shouldSummarize() throws Exception {
|
||||
final DoubleSummaryStatistics result = givenList.stream().collect(summarizingDouble(String::length));
|
||||
|
||||
assertThat(result.getAverage()).isEqualTo(2);
|
||||
assertThat(result.getCount()).isEqualTo(4);
|
||||
assertThat(result.getMax()).isEqualTo(3);
|
||||
assertThat(result.getMin()).isEqualTo(1);
|
||||
assertThat(result.getSum()).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAveraging_shouldAverage() throws Exception {
|
||||
final Double result = givenList.stream().collect(averagingDouble(String::length));
|
||||
|
||||
assertThat(result).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSumming_shouldSum() throws Exception {
|
||||
final Double result = givenList.stream().filter(i -> true).collect(summingDouble(String::length));
|
||||
|
||||
assertThat(result).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenMaxingBy_shouldMaxBy() throws Exception {
|
||||
final Optional<String> result = givenList.stream().collect(maxBy(Comparator.naturalOrder()));
|
||||
|
||||
assertThat(result).isPresent().hasValue("dd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGroupingBy_shouldGroupBy() throws Exception {
|
||||
final Map<Integer, Set<String>> result = givenList.stream().collect(groupingBy(String::length, toSet()));
|
||||
|
||||
assertThat(result).containsEntry(1, newHashSet("a")).containsEntry(2, newHashSet("bb", "dd")).containsEntry(3, newHashSet("ccc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCreatingCustomCollector_shouldCollect() throws Exception {
|
||||
final ImmutableSet<String> result = givenList.stream().collect(toImmutableSet());
|
||||
|
||||
assertThat(result).isInstanceOf(ImmutableSet.class).contains("a", "bb", "ccc", "dd");
|
||||
|
||||
}
|
||||
|
||||
private static <T> ImmutableSetCollector<T> toImmutableSet() {
|
||||
return new ImmutableSetCollector<>();
|
||||
}
|
||||
|
||||
private static class ImmutableSetCollector<T> implements Collector<T, ImmutableSet.Builder<T>, ImmutableSet<T>> {
|
||||
|
||||
@Override
|
||||
public Supplier<ImmutableSet.Builder<T>> supplier() {
|
||||
return ImmutableSet::builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiConsumer<ImmutableSet.Builder<T>, T> accumulator() {
|
||||
return ImmutableSet.Builder::add;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryOperator<ImmutableSet.Builder<T>> combiner() {
|
||||
return (left, right) -> left.addAll(right.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<ImmutableSet.Builder<T>, ImmutableSet<T>> finisher() {
|
||||
return ImmutableSet.Builder::build;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Characteristics> characteristics() {
|
||||
return Sets.immutableEnumSet(Characteristics.UNORDERED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -21,30 +21,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source.version}</source>
|
||||
<target>${maven.compiler.target.version}</target>
|
||||
<compilerArgs>--enable-preview</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>--enable-preview</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>12</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>12</maven.compiler.target.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
-13
@@ -19,19 +19,6 @@ public class SwitchUnitTest {
|
||||
Assert.assertEquals(value, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchLocalVariable(){
|
||||
var month = Month.AUG;
|
||||
int i = switch (month){
|
||||
case JAN,JUN, JUL -> 3;
|
||||
case FEB,SEP, OCT, NOV, DEC -> 1;
|
||||
case MAR,MAY, APR, AUG -> {
|
||||
int j = month.toString().length() * 4;
|
||||
break j;
|
||||
}
|
||||
};
|
||||
Assert.assertEquals(12, i);
|
||||
}
|
||||
|
||||
enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}
|
||||
}
|
||||
|
||||
@@ -8,39 +8,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source.version}</source>
|
||||
<target>${maven.compiler.target.version}</target>
|
||||
<release>13</release>
|
||||
<compilerArgs>--enable-preview</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire.plugin.version}</version>
|
||||
<configuration>
|
||||
<argLine>--enable-preview</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>13</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>13</maven.compiler.target.version>
|
||||
<surefire.plugin.version>3.0.0-M3</surefire.plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
-1
@@ -7,7 +7,6 @@ import org.junit.Test;
|
||||
public class SwitchExpressionsWithYieldUnitTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("preview")
|
||||
public void whenSwitchingOnOperationSquareMe_thenWillReturnSquare() {
|
||||
var me = 4;
|
||||
var operation = "squareMe";
|
||||
|
||||
-2
@@ -8,7 +8,6 @@ public class TextBlocksUnitTest {
|
||||
|
||||
private static final String JSON_STRING = "{\r\n" + "\"name\" : \"Baeldung\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private static final String TEXT_BLOCK_JSON = """
|
||||
{
|
||||
"name" : "Baeldung",
|
||||
@@ -25,7 +24,6 @@ public class TextBlocksUnitTest {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Test
|
||||
public void whenTextBlocks_thenFormattedWorksAsFormat() {
|
||||
assertThat(TEXT_BLOCK_JSON.formatted("baeldung")
|
||||
|
||||
-4
@@ -13,7 +13,6 @@ import org.junit.Test;
|
||||
public class SwitchExpressionsUnitTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings ("preview")
|
||||
public void whenSwitchingOverMonthJune_thenWillReturn3() {
|
||||
|
||||
var month = JUNE;
|
||||
@@ -29,7 +28,6 @@ public class SwitchExpressionsUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings ("preview")
|
||||
public void whenSwitchingOverMonthAugust_thenWillReturn24() {
|
||||
var month = AUGUST;
|
||||
|
||||
@@ -47,7 +45,6 @@ public class SwitchExpressionsUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings ("preview")
|
||||
public void whenSwitchingOverMonthJanuary_thenWillReturn3() {
|
||||
|
||||
Function<Month, Integer> func = (month) -> {
|
||||
@@ -61,7 +58,6 @@ public class SwitchExpressionsUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings ("preview")
|
||||
public void whenSwitchingOverMonthAugust_thenWillReturn2() {
|
||||
var month = AUGUST;
|
||||
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -27,33 +26,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<release>${maven.compiler.release}</release>
|
||||
<compilerArgs>--enable-preview</compilerArgs>
|
||||
<source>14</source>
|
||||
<target>14</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire.plugin.version}</version>
|
||||
<configuration>
|
||||
<argLine>--enable-preview</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.release>15</maven.compiler.release>
|
||||
<surefire.plugin.version>3.0.0-M3</surefire.plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -4,5 +4,4 @@
|
||||
- [Guide to mapMulti in Stream API](https://www.baeldung.com/java-mapmulti)
|
||||
- [Collecting Stream Elements into a List in Java](https://www.baeldung.com/java-stream-to-list-collecting)
|
||||
- [New Features in Java 16](https://www.baeldung.com/java-16-new-features)
|
||||
- [Guide to Java 8 groupingBy Collector](https://www.baeldung.com/java-groupingby-collector)
|
||||
- [Value-Based Classes in Java](https://www.baeldung.com/java-value-based-classes)
|
||||
|
||||
@@ -8,3 +8,5 @@
|
||||
- [Sealed Classes and Interfaces in Java](https://www.baeldung.com/java-sealed-classes-interfaces)
|
||||
- [Migrate From Java 8 to Java 17](https://www.baeldung.com/java-migrate-8-to-17)
|
||||
- [Format Multiple ‘or’ Conditions in an If Statement in Java](https://www.baeldung.com/java-multiple-or-conditions-if-statement)
|
||||
- [Get All Record Fields and Its Values via Reflection](https://www.baeldung.com/java-reflection-record-fields-values)
|
||||
- [Context-Specific Deserialization Filters in Java 17](https://www.baeldung.com/java-context-specific-deserialization-filters)
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.deserializationfilters;
|
||||
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.util.function.BinaryOperator;
|
||||
|
||||
import com.baeldung.deserializationfilters.service.DeserializationService;
|
||||
import com.baeldung.deserializationfilters.service.LimitedArrayService;
|
||||
import com.baeldung.deserializationfilters.service.LowDepthService;
|
||||
import com.baeldung.deserializationfilters.service.SmallObjectService;
|
||||
import com.baeldung.deserializationfilters.utils.FilterUtils;
|
||||
|
||||
public class ContextSpecificDeserializationFilterFactory implements BinaryOperator<ObjectInputFilter> {
|
||||
|
||||
@Override
|
||||
public ObjectInputFilter apply(ObjectInputFilter current, ObjectInputFilter next) {
|
||||
if (current == null) {
|
||||
Class<?> caller = findInStack(DeserializationService.class);
|
||||
|
||||
if (caller == null) {
|
||||
current = FilterUtils.fallbackFilter();
|
||||
} else if (caller.equals(SmallObjectService.class)) {
|
||||
current = FilterUtils.safeSizeFilter(190);
|
||||
} else if (caller.equals(LowDepthService.class)) {
|
||||
current = FilterUtils.safeDepthFilter(2);
|
||||
} else if (caller.equals(LimitedArrayService.class)) {
|
||||
current = FilterUtils.safeArrayFilter(3);
|
||||
}
|
||||
}
|
||||
|
||||
return ObjectInputFilter.merge(current, next);
|
||||
}
|
||||
|
||||
private static Class<?> findInStack(Class<?> superType) {
|
||||
for (StackTraceElement element : Thread.currentThread()
|
||||
.getStackTrace()) {
|
||||
try {
|
||||
Class<?> subType = Class.forName(element.getClassName());
|
||||
if (superType.isAssignableFrom(subType)) {
|
||||
return subType;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.deserializationfilters.pojo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface ContextSpecific extends Serializable {
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.deserializationfilters.pojo;
|
||||
|
||||
public class NestedSample implements ContextSpecific {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Sample optional;
|
||||
|
||||
public NestedSample(Sample optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
public Sample getOptional() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
public void setOptional(Sample optional) {
|
||||
this.optional = optional;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.baeldung.deserializationfilters.pojo;
|
||||
|
||||
public class Sample implements ContextSpecific, Comparable<Sample> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int[] array;
|
||||
private String name;
|
||||
private NestedSample nested;
|
||||
|
||||
public Sample(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Sample(int[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
public Sample(NestedSample nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int[] getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setArray(int[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
public NestedSample getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(NestedSample nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Sample o) {
|
||||
if (name == null)
|
||||
return -1;
|
||||
|
||||
if (o == null || o.getName() == null)
|
||||
return 1;
|
||||
|
||||
return getName().compareTo(o.getName());
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.deserializationfilters.pojo;
|
||||
|
||||
public class SampleExploit extends Sample {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SampleExploit() {
|
||||
super("exploit");
|
||||
}
|
||||
|
||||
public static void maliciousCode() {
|
||||
System.out.println("exploit executed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
maliciousCode();
|
||||
return "exploit";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Sample o) {
|
||||
maliciousCode();
|
||||
return super.compareTo(o);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.deserializationfilters.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
|
||||
public interface DeserializationService {
|
||||
|
||||
Set<ContextSpecific> process(InputStream... inputStreams);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.deserializationfilters.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
|
||||
|
||||
public class LimitedArrayService implements DeserializationService {
|
||||
|
||||
@Override
|
||||
public Set<ContextSpecific> process(InputStream... inputStreams) {
|
||||
return DeserializationUtils.deserializeIntoSet(inputStreams);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.deserializationfilters.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.util.Set;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
|
||||
|
||||
public class LowDepthService implements DeserializationService {
|
||||
|
||||
public Set<ContextSpecific> process(ObjectInputFilter filter, InputStream... inputStreams) {
|
||||
return DeserializationUtils.deserializeIntoSet(filter, inputStreams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ContextSpecific> process(InputStream... inputStreams) {
|
||||
return process(null, inputStreams);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.deserializationfilters.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
|
||||
|
||||
public class SmallObjectService implements DeserializationService {
|
||||
|
||||
@Override
|
||||
public Set<ContextSpecific> process(InputStream... inputStreams) {
|
||||
return DeserializationUtils.deserializeIntoSet(inputStreams);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baeldung.deserializationfilters.utils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
|
||||
public class DeserializationUtils {
|
||||
private DeserializationUtils() {
|
||||
}
|
||||
|
||||
public static Object deserialize(InputStream inStream) {
|
||||
return deserialize(inStream, null);
|
||||
}
|
||||
|
||||
public static Object deserialize(InputStream inStream, ObjectInputFilter filter) {
|
||||
try (ObjectInputStream in = new ObjectInputStream(inStream)) {
|
||||
if (filter != null) {
|
||||
in.setObjectInputFilter(filter);
|
||||
}
|
||||
return in.readObject();
|
||||
} catch (InvalidClassException e) {
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<ContextSpecific> deserializeIntoSet(InputStream... inputStreams) {
|
||||
return deserializeIntoSet(null, inputStreams);
|
||||
}
|
||||
|
||||
public static Set<ContextSpecific> deserializeIntoSet(ObjectInputFilter filter, InputStream... inputStreams) {
|
||||
Set<ContextSpecific> set = new TreeSet<>();
|
||||
|
||||
for (InputStream inputStream : inputStreams) {
|
||||
Object object = deserialize(inputStream, filter);
|
||||
if (object != null) {
|
||||
set.add((ContextSpecific) object);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.baeldung.deserializationfilters.utils;
|
||||
|
||||
import java.io.ObjectInputFilter;
|
||||
|
||||
public class FilterUtils {
|
||||
|
||||
private static final String DEFAULT_PACKAGE_PATTERN = "java.base/*;!*";
|
||||
private static final String POJO_PACKAGE = "com.baeldung.deserializationfilters.pojo";
|
||||
|
||||
private FilterUtils() {
|
||||
}
|
||||
|
||||
private static ObjectInputFilter baseFilter(String parameter, int max) {
|
||||
return ObjectInputFilter.Config.createFilter(String.format("%s=%d;%s.**;%s", parameter, max, POJO_PACKAGE, DEFAULT_PACKAGE_PATTERN));
|
||||
}
|
||||
|
||||
public static ObjectInputFilter fallbackFilter() {
|
||||
return ObjectInputFilter.Config.createFilter(String.format("%s", DEFAULT_PACKAGE_PATTERN));
|
||||
}
|
||||
|
||||
public static ObjectInputFilter safeSizeFilter(int max) {
|
||||
return baseFilter("maxbytes", max);
|
||||
}
|
||||
|
||||
public static ObjectInputFilter safeArrayFilter(int max) {
|
||||
return baseFilter("maxarray", max);
|
||||
}
|
||||
|
||||
public static ObjectInputFilter safeDepthFilter(int max) {
|
||||
return baseFilter("maxdepth", max);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.deserializationfilters.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SerializationUtils {
|
||||
|
||||
private SerializationUtils() {
|
||||
}
|
||||
|
||||
public static void serialize(Object object, OutputStream outStream) throws IOException {
|
||||
try (ObjectOutputStream objStream = new ObjectOutputStream(outStream)) {
|
||||
objStream.writeObject(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package com.baeldung.deserializationfilters;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.deserializationfilters.pojo.ContextSpecific;
|
||||
import com.baeldung.deserializationfilters.pojo.NestedSample;
|
||||
import com.baeldung.deserializationfilters.pojo.Sample;
|
||||
import com.baeldung.deserializationfilters.pojo.SampleExploit;
|
||||
import com.baeldung.deserializationfilters.service.LimitedArrayService;
|
||||
import com.baeldung.deserializationfilters.service.LowDepthService;
|
||||
import com.baeldung.deserializationfilters.service.SmallObjectService;
|
||||
import com.baeldung.deserializationfilters.utils.DeserializationUtils;
|
||||
import com.baeldung.deserializationfilters.utils.FilterUtils;
|
||||
import com.baeldung.deserializationfilters.utils.SerializationUtils;
|
||||
|
||||
public class ContextSpecificDeserializationFilterIntegrationTest {
|
||||
|
||||
private static ByteArrayOutputStream serialSampleA = new ByteArrayOutputStream();
|
||||
private static ByteArrayOutputStream serialBigSampleA = new ByteArrayOutputStream();
|
||||
|
||||
private static ByteArrayOutputStream serialSampleB = new ByteArrayOutputStream();
|
||||
private static ByteArrayOutputStream serialBigSampleB = new ByteArrayOutputStream();
|
||||
|
||||
private static ByteArrayOutputStream serialSampleC = new ByteArrayOutputStream();
|
||||
private static ByteArrayOutputStream serialBigSampleC = new ByteArrayOutputStream();
|
||||
|
||||
private static ByteArrayInputStream bytes(ByteArrayOutputStream stream) {
|
||||
return new ByteArrayInputStream(stream.toByteArray());
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws IOException {
|
||||
ObjectInputFilter.Config.setSerialFilterFactory(new ContextSpecificDeserializationFilterFactory());
|
||||
|
||||
SerializationUtils.serialize(new Sample("simple"), serialSampleA);
|
||||
SerializationUtils.serialize(new SampleExploit(), serialBigSampleA);
|
||||
|
||||
SerializationUtils.serialize(new Sample(new int[] { 1, 2, 3 }), serialSampleB);
|
||||
SerializationUtils.serialize(new Sample(new int[] { 1, 2, 3, 4, 5, 6 }), serialBigSampleB);
|
||||
|
||||
SerializationUtils.serialize(new Sample(new NestedSample(null)), serialSampleC);
|
||||
SerializationUtils.serialize(new Sample(new NestedSample(new Sample("deep"))), serialBigSampleC);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenSmallObjectContext_thenCorrectFilterApplied() {
|
||||
Set<ContextSpecific> result = new SmallObjectService().process( //
|
||||
bytes(serialSampleA), //
|
||||
bytes(serialBigSampleA));
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("simple", ((Sample) result.iterator()
|
||||
.next()).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenLimitedArrayContext_thenCorrectFilterApplied() {
|
||||
Set<ContextSpecific> result = new LimitedArrayService().process( //
|
||||
bytes(serialSampleB), //
|
||||
bytes(serialBigSampleB));
|
||||
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenLowDepthContext_thenCorrectFilterApplied() {
|
||||
Set<ContextSpecific> result = new LowDepthService().process( //
|
||||
bytes(serialSampleC), //
|
||||
bytes(serialBigSampleC));
|
||||
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenExtraFilter_whenCombinedContext_thenMergedFiltersApplied() {
|
||||
Set<ContextSpecific> result = new LowDepthService().process( //
|
||||
FilterUtils.safeSizeFilter(190), //
|
||||
bytes(serialSampleA), //
|
||||
bytes(serialBigSampleA), //
|
||||
bytes(serialSampleC), //
|
||||
bytes(serialBigSampleC));
|
||||
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("simple", ((Sample) result.iterator()
|
||||
.next()).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFallbackContext_whenUsingBaseClasses_thenRestrictiveFilterApplied() throws IOException {
|
||||
String a = new String("a");
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
SerializationUtils.serialize(a, outStream);
|
||||
|
||||
String deserializedA = (String) DeserializationUtils.deserialize(bytes(outStream));
|
||||
|
||||
assertEquals(a, deserializedA);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFallbackContext_whenUsingAppClasses_thenRejected() throws IOException {
|
||||
Sample a = new Sample("a");
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
SerializationUtils.serialize(a, outStream);
|
||||
|
||||
Sample deserializedA = (Sample) DeserializationUtils.deserialize(bytes(outStream));
|
||||
|
||||
assertNull(deserializedA);
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.baeldung.recordproperties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
record Player(String name, int age, Long score) {
|
||||
}
|
||||
|
||||
public class ReadRecordPropertiesByReflectionUnitTest {
|
||||
private static final Player ERIC = new Player("Eric", 28, 4242L);
|
||||
|
||||
@Test
|
||||
void whenUsingRecordComponent_thenGetExpectedResult() {
|
||||
var fields = new ArrayList<Field>();
|
||||
RecordComponent[] components = Player.class.getRecordComponents();
|
||||
for (var comp : components) {
|
||||
try {
|
||||
Field field = ERIC.getClass()
|
||||
.getDeclaredField(comp.getName());
|
||||
field.setAccessible(true);
|
||||
fields.add(field);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// for simplicity, error handling is skipped
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(3, fields.size());
|
||||
|
||||
var nameField = fields.get(0);
|
||||
var ageField = fields.get(1);
|
||||
var scoreField = fields.get(2);
|
||||
try {
|
||||
assertEquals("name", nameField.getName());
|
||||
assertEquals(String.class, nameField.getType());
|
||||
assertEquals("Eric", nameField.get(ERIC));
|
||||
|
||||
assertEquals("age", ageField.getName());
|
||||
assertEquals(int.class, ageField.getType());
|
||||
assertEquals(28, ageField.get(ERIC));
|
||||
|
||||
assertEquals("score", scoreField.getName());
|
||||
assertEquals(Long.class, scoreField.getType());
|
||||
assertEquals(4242L, scoreField.get(ERIC));
|
||||
} catch (IllegalAccessException exception) {
|
||||
// for simplicity, error handling is skipped
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingClassGetDeclaredField_thenGetExpectedResult() {
|
||||
// record has no public fields
|
||||
assertEquals(0, Player.class.getFields().length);
|
||||
|
||||
var fields = new ArrayList<Field>();
|
||||
for (var field : Player.class.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
fields.add(field);
|
||||
}
|
||||
|
||||
assertEquals(3, fields.size());
|
||||
var nameField = fields.get(0);
|
||||
var ageField = fields.get(1);
|
||||
var scoreField = fields.get(2);
|
||||
|
||||
try {
|
||||
assertEquals("name", nameField.getName());
|
||||
assertEquals(String.class, nameField.getType());
|
||||
assertEquals("Eric", nameField.get(ERIC));
|
||||
|
||||
assertEquals("age", ageField.getName());
|
||||
assertEquals(int.class, ageField.getType());
|
||||
assertEquals(28, ageField.get(ERIC));
|
||||
|
||||
assertEquals("score", scoreField.getName());
|
||||
assertEquals(Long.class, scoreField.getType());
|
||||
assertEquals(4242L, scoreField.get(ERIC));
|
||||
} catch (IllegalAccessException ex) {
|
||||
// for simplicity, error handling is skipped
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -18,19 +18,19 @@ public class VehicleUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCar_whenUsingReflectionAPI_thenSuperClassIsSealed() {
|
||||
public void givenCar_whenUsingReflectionAPI_thenSuperClassIsSealed() throws ClassNotFoundException {
|
||||
Assertions.assertThat(car.getClass().isSealed()).isEqualTo(false);
|
||||
Assertions.assertThat(car.getClass().getSuperclass().isSealed()).isEqualTo(true);
|
||||
Assertions.assertThat(car.getClass().getSuperclass().getPermittedSubclasses())
|
||||
.contains(ClassDesc.of(car.getClass().getCanonicalName()));
|
||||
.contains(Class.forName(car.getClass().getCanonicalName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTruck_whenUsingReflectionAPI_thenSuperClassIsSealed() {
|
||||
public void givenTruck_whenUsingReflectionAPI_thenSuperClassIsSealed() throws ClassNotFoundException {
|
||||
Assertions.assertThat(truck.getClass().isSealed()).isEqualTo(false);
|
||||
Assertions.assertThat(truck.getClass().getSuperclass().isSealed()).isEqualTo(true);
|
||||
Assertions.assertThat(truck.getClass().getSuperclass().getPermittedSubclasses())
|
||||
.contains(ClassDesc.of(truck.getClass().getCanonicalName()));
|
||||
.contains(Class.forName(truck.getClass().getCanonicalName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+6
-6
@@ -18,19 +18,19 @@ public class VehicleUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCar_whenUsingReflectionAPI_thenInterfaceIsSealed() {
|
||||
public void givenCar_whenUsingReflectionAPI_thenInterfaceIsSealed() throws ClassNotFoundException {
|
||||
Assertions.assertThat(car.getClass().isSealed()).isEqualTo(false);
|
||||
Assertions.assertThat(car.getClass().getInterfaces()[0].isSealed()).isEqualTo(true);
|
||||
Assertions.assertThat(car.getClass().getInterfaces()[0].permittedSubclasses())
|
||||
.contains(ClassDesc.of(car.getClass().getCanonicalName()));
|
||||
Assertions.assertThat(car.getClass().getInterfaces()[0].getPermittedSubclasses())
|
||||
.contains(Class.forName(car.getClass().getCanonicalName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTruck_whenUsingReflectionAPI_thenInterfaceIsSealed() {
|
||||
public void givenTruck_whenUsingReflectionAPI_thenInterfaceIsSealed() throws ClassNotFoundException {
|
||||
Assertions.assertThat(truck.getClass().isSealed()).isEqualTo(false);
|
||||
Assertions.assertThat(truck.getClass().getInterfaces()[0].isSealed()).isEqualTo(true);
|
||||
Assertions.assertThat(truck.getClass().getInterfaces()[0].permittedSubclasses())
|
||||
.contains(ClassDesc.of(truck.getClass().getCanonicalName()));
|
||||
Assertions.assertThat(truck.getClass().getInterfaces()[0].getPermittedSubclasses())
|
||||
.contains(Class.forName(truck.getClass().getCanonicalName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
## Relevant Articles
|
||||
- [Deprecate Finalization in Java 18](https://www.baeldung.com/java-18-deprecate-finalization)
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.deserialization;
|
||||
|
||||
public record Contact(String email, String phone) {
|
||||
// Constructor, getters, and other methods are automatically generated
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.deserialization;
|
||||
|
||||
public record Person(String name, int age, String address, Contact contact) {
|
||||
// Constructor, getters, and other methods are automatically generated
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.baeldung.deserialization;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class DeserializationUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenJsonString_whenDeserialized_thenPersonRecordCreated() {
|
||||
String json = "{\"name\":\"John Doe\",\"age\":30,\"address\":\"123 Main St\"}";
|
||||
|
||||
Person person = new Gson().fromJson(json, Person.class);
|
||||
|
||||
assertEquals("John Doe", person.name());
|
||||
assertEquals(30, person.age());
|
||||
assertEquals("123 Main St", person.address());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNestedJsonString_whenDeserialized_thenPersonRecordCreated() {
|
||||
String json = "{\"name\":\"John Doe\",\"age\":30,\"address\":\"123 Main St\",\"contact\":{\"email\":\"john.doe@example.com\",\"phone\":\"555-1234\"}}";
|
||||
|
||||
Person person = new Gson().fromJson(json, Person.class);
|
||||
|
||||
assertNotNull(person);
|
||||
assertEquals("John Doe", person.name());
|
||||
assertEquals(30, person.age());
|
||||
assertEquals("123 Main St", person.address());
|
||||
|
||||
Contact contact = person.contact();
|
||||
|
||||
assertNotNull(contact);
|
||||
assertEquals("john.doe@example.com", contact.email());
|
||||
assertEquals("555-1234", contact.phone());
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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-21</artifactId>
|
||||
<name>core-java-21</name>
|
||||
@@ -12,12 +12,6 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>21</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>21</maven.compiler.target.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -44,4 +38,10 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source.version>21</maven.compiler.source.version>
|
||||
<maven.compiler.target.version>21</maven.compiler.target.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -6,4 +6,7 @@
|
||||
- [How Many Days Are There in a Particular Month of a Given Year?](https://www.baeldung.com/days-particular-month-given-year)
|
||||
- [Difference Between Instant and LocalDateTime](https://www.baeldung.com/java-instant-vs-localdatetime)
|
||||
- [Add Minutes to a Time String in Java](https://www.baeldung.com/java-string-time-add-mins)
|
||||
- [Round the Date in Java](https://www.baeldung.com/java-round-the-date)
|
||||
- [Representing Furthest Possible Date in Java](https://www.baeldung.com/java-date-represent-max)
|
||||
- [Retrieving Unix Time in Java](https://www.baeldung.com/java-retrieve-unix-time)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-datetime-java8-1)
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<joda-time.version>2.10</joda-time.version>
|
||||
<joda-time.version>2.12.5</joda-time.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.maxdate;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class DateComparison {
|
||||
public int compareTodayWithMaxDate() {
|
||||
Date today = new Date();
|
||||
Date maxDate = new Date(Long.MAX_VALUE);
|
||||
|
||||
int comparisonResult = today.compareTo(maxDate);
|
||||
return comparisonResult;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DateComparison comparator = new DateComparison();
|
||||
System.out.println(comparator.compareTodayWithMaxDate());
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.maxdate;
|
||||
|
||||
import java.util.Date;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class MaxDateDisplay {
|
||||
public String getMaxDateValue() {
|
||||
Date maxDate = new Date(Long.MAX_VALUE);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
return "The maximum date value in Java is: " + sdf.format(maxDate);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
MaxDateDisplay display = new MaxDateDisplay();
|
||||
System.out.println(display.getMaxDateValue());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import java.util.List;
|
||||
|
||||
public class SimpleParseDate {
|
||||
|
||||
public Date parseDate(String dateString, List<String> formatStrings) {
|
||||
public static Date parseDate(String dateString, List<String> formatStrings) {
|
||||
for (String formatString : formatStrings) {
|
||||
try {
|
||||
return new SimpleDateFormat(formatString).parse(dateString);
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.baeldung.rounddate;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class RoundDate {
|
||||
public static Date getDate(int year, int month, int day, int hour, int minute) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, month);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
calendar.set(Calendar.MINUTE, minute);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static Date roundToDay(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static Date roundToNearestUnit(Date date, int unit) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
|
||||
switch (unit) {
|
||||
case Calendar.HOUR:
|
||||
int minute = calendar.get(Calendar.MINUTE);
|
||||
if (minute >= 0 && minute < 15) {
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
} else if (minute >= 15 && minute < 45) {
|
||||
calendar.set(Calendar.MINUTE, 30);
|
||||
} else {
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.add(Calendar.HOUR_OF_DAY, 1);
|
||||
}
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
break;
|
||||
|
||||
case Calendar.DAY_OF_MONTH:
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
if (hour >= 12) {
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
break;
|
||||
|
||||
case Calendar.MONTH:
|
||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
if (day >= 15) {
|
||||
calendar.add(Calendar.MONTH, 1);
|
||||
}
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static LocalDateTime roundToStartOfMonthUsingLocalDateTime(LocalDateTime dateTime) {
|
||||
return dateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
}
|
||||
|
||||
public static LocalDateTime roundToEndOfWeekUsingLocalDateTime(LocalDateTime dateTime) {
|
||||
return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY))
|
||||
.withHour(23)
|
||||
.withMinute(59)
|
||||
.withSecond(59)
|
||||
.withNano(999);
|
||||
}
|
||||
|
||||
public static ZonedDateTime roundToStartOfMonthUsingZonedDateTime(ZonedDateTime dateTime) {
|
||||
return dateTime.withDayOfMonth(1)
|
||||
.withHour(0)
|
||||
.withMinute(0)
|
||||
.withSecond(0)
|
||||
.with(ChronoField.MILLI_OF_SECOND, 0)
|
||||
.with(ChronoField.MICRO_OF_SECOND, 0)
|
||||
.with(ChronoField.NANO_OF_SECOND, 0);
|
||||
}
|
||||
|
||||
public static ZonedDateTime roundToEndOfWeekUsingZonedDateTime(ZonedDateTime dateTime) {
|
||||
return dateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY))
|
||||
.withHour(23)
|
||||
.withMinute(59)
|
||||
.withSecond(59)
|
||||
.with(ChronoField.MILLI_OF_SECOND, 999)
|
||||
.with(ChronoField.MICRO_OF_SECOND, 999)
|
||||
.with(ChronoField.NANO_OF_SECOND, 999);
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.maxdate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DateComparisonUnitTest {
|
||||
|
||||
@Test
|
||||
void whenCompareTodayWithMaxDate_thenCorrectResult() {
|
||||
DateComparison comparator = new DateComparison();
|
||||
int result = comparator.compareTodayWithMaxDate();
|
||||
|
||||
assertTrue(result < 0);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.maxdate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MaxDateDisplayUnitTest {
|
||||
|
||||
@Test
|
||||
void whenGetMaxDate_thenCorrectResult() {
|
||||
MaxDateDisplay display = new MaxDateDisplay();
|
||||
String result = display.getMaxDateValue();
|
||||
assertEquals(
|
||||
"The maximum date value in Java is: 292278994-08-17 07:12:55.807",
|
||||
result
|
||||
);
|
||||
}
|
||||
}
|
||||
+20
-22
@@ -1,43 +1,41 @@
|
||||
package com.baeldung.parsingDates;
|
||||
|
||||
import com.baeldung.parsingDates.SimpleDateTimeFormat;
|
||||
import com.baeldung.parsingDates.SimpleDateTimeFormater;
|
||||
import com.baeldung.parsingDates.SimpleDateUtils;
|
||||
import com.baeldung.parsingDates.SimpleParseDate;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Arrays;
|
||||
import org.junit.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SimpleParseDateUnitTest {
|
||||
class SimpleParseDateUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenInvalidInput_thenGettingUnexpectedResult() {
|
||||
SimpleParseDate simpleParseDate = new SimpleParseDate();
|
||||
void whenInvalidInput_thenGettingUnexpectedResult() {
|
||||
String date = "2022-40-40";
|
||||
assertEquals("Sat May 10 00:00:00 UTC 2025", simpleParseDate.parseDate(date, Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd")).toString());
|
||||
assertEquals("Sat May 10 00:00:00 UTC 2025", SimpleParseDate.parseDate(date, Arrays.asList("MM/dd/yyyy", "dd.MM.yyyy", "yyyy-MM-dd"))
|
||||
.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenInvalidDate_thenAssertThrows() {
|
||||
SimpleDateTimeFormater simpleDateTimeFormater = new SimpleDateTimeFormater();
|
||||
assertEquals(java.time.LocalDate.parse("2022-12-04"), simpleDateTimeFormater.parseDate("2022-12-04"));
|
||||
assertThrows(DateTimeParseException.class, () -> simpleDateTimeFormater.parseDate("2022-13-04"));
|
||||
void whenInvalidDate_thenAssertThrows() {
|
||||
assertEquals(java.time.LocalDate.parse("2022-12-04"), SimpleDateTimeFormater.parseDate("2022-12-04"));
|
||||
assertThrows(DateTimeParseException.class, () -> SimpleDateTimeFormater.parseDate("2022-13-04"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDateIsCorrect_thenParseCorrect() {
|
||||
SimpleDateUtils simpleDateUtils = new SimpleDateUtils();
|
||||
assertNull(simpleDateUtils.parseDate("53/10/2014"));
|
||||
assertEquals("Wed Sep 10 00:00:00 UTC 2014", simpleDateUtils.parseDate("10/09/2014").toString());
|
||||
void whenDateIsCorrect_thenParseCorrect() {
|
||||
assertNull(SimpleDateUtils.parseDate("53/10/2014"));
|
||||
assertEquals("Wed Sep 10 00:00:00 UTC 2014", SimpleDateUtils.parseDate("10/09/2014")
|
||||
.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDateIsCorrect_thenResultCorrect() {
|
||||
SimpleDateTimeFormat simpleDateTimeFormat = new SimpleDateTimeFormat();
|
||||
assertNull(simpleDateTimeFormat.parseDate("53/10/2014"));
|
||||
assertEquals(LocalDate.parse("2014-10-10"), simpleDateTimeFormat.parseDate("2014-10-10"));
|
||||
void whenDateIsCorrect_thenResultCorrect() {
|
||||
assertNull(SimpleDateTimeFormat.parseDate("53/10/2014"));
|
||||
assertEquals(LocalDate.parse("2014-10-10"), SimpleDateTimeFormat.parseDate("2014-10-10"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.baeldung.rounddate;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class DateRoundingUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenDate_whenRoundToDay_thenBeginningOfDay() {
|
||||
Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 30);
|
||||
Date result = RoundDate.roundToDay(date);
|
||||
assertEquals(RoundDate.getDate(2023, Calendar.JANUARY, 27, 0, 0), result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDate_whenRoundToNearestUnit_thenNearestUnit() {
|
||||
Date date = RoundDate.getDate(2023, Calendar.JANUARY, 27, 14, 12);
|
||||
Date result = RoundDate.roundToNearestUnit(date, Calendar.DAY_OF_MONTH);
|
||||
Date expected = RoundDate.getDate(2023, Calendar.JANUARY, 28, 0, 0);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenLocalDateTime_whenRoundToStartOfMonth_thenStartOfMonth() {
|
||||
LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12);
|
||||
LocalDateTime result = RoundDate.roundToStartOfMonthUsingLocalDateTime(dateTime);
|
||||
LocalDateTime expected = LocalDateTime.of(2023, 1, 1, 0, 0, 0);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void givenZonedDateTime_whenRoundToStartOfMonth_thenStartOfMonth() {
|
||||
ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault());
|
||||
ZonedDateTime result = RoundDate.roundToStartOfMonthUsingZonedDateTime(dateTime);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2023, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenLocalDateTime_whenRoundToEndOfWeek_thenEndOfWeek() {
|
||||
LocalDateTime dateTime = LocalDateTime.of(2023, 1, 27, 14, 12);
|
||||
LocalDateTime result = RoundDate.roundToEndOfWeekUsingLocalDateTime(dateTime);
|
||||
LocalDateTime expected = LocalDateTime.of(2023, 1, 28, 23, 59, 59, 999);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenZonedDateTime_whenRoundToEndOfWeek_thenEndOfWeek() {
|
||||
ZonedDateTime dateTime = ZonedDateTime.of(2023, 1, 27, 14, 12, 0, 0, ZoneId.systemDefault());
|
||||
ZonedDateTime result = RoundDate.roundToEndOfWeekUsingZonedDateTime(dateTime);
|
||||
ZonedDateTime expected = ZonedDateTime.of(2023, 1, 28, 23, 59, 59, 999, ZoneId.systemDefault());
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.unixtime;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import java.time.Month;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class UnixTimeUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenTimeUsingDateApi_whenConvertedToUnixTime_thenMatch() {
|
||||
Date date = new Date(2023 - 1900, 1, 15, 0, 0, 0);
|
||||
long expected = 1676419200;
|
||||
long actual = date.getTime() / 1000L;
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTimeUsingJodaTime_whenConvertedToUnixTime_thenMatch() {
|
||||
DateTime dateTime = new DateTime(2023, 2, 15, 00, 00, 00, 0);
|
||||
long expected = 1676419200;
|
||||
long actual = dateTime.getMillis() / 1000L;
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTimeUsingLocalDate_whenConvertedToUnixTime_thenMatch() {
|
||||
LocalDate date = LocalDate.of(2023, Month.FEBRUARY, 15);
|
||||
Instant instant = date.atStartOfDay().atZone(ZoneId.of("UTC")).toInstant();
|
||||
long expected = 1676419200;
|
||||
long actual = instant.getEpochSecond();
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,7 +56,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<joda-time.version>2.10</joda-time.version>
|
||||
<joda-time.version>2.12.5</joda-time.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -11,5 +11,5 @@ This module contains articles about Java 8 core features
|
||||
- [Finding Min/Max in an Array with Java](https://www.baeldung.com/java-array-min-max)
|
||||
- [Internationalization and Localization in Java 8](https://www.baeldung.com/java-8-localization)
|
||||
- [Generalized Target-Type Inference in Java](https://www.baeldung.com/java-generalized-target-type-inference)
|
||||
- [Monads in Java](https://www.baeldung.com/java-monads)
|
||||
- [Monads in Java – Optional](https://www.baeldung.com/java-monads)
|
||||
- [[More -->]](/core-java-modules/core-java-8-2)
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.baeldung.spliterator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class CustomSpliterator implements Spliterator<Integer> {
|
||||
private final List<Integer> elements;
|
||||
private int currentIndex;
|
||||
|
||||
public CustomSpliterator(List<Integer> elements) {
|
||||
this.elements = elements;
|
||||
this.currentIndex = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Integer> action) {
|
||||
if (currentIndex < elements.size()) {
|
||||
action.accept(elements.get(currentIndex));
|
||||
currentIndex++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Integer> trySplit() {
|
||||
int currentSize = elements.size() - currentIndex;
|
||||
if (currentSize < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int splitIndex = currentIndex + currentSize / 2;
|
||||
CustomSpliterator newSpliterator = new CustomSpliterator(elements.subList(currentIndex, splitIndex));
|
||||
currentIndex = splitIndex;
|
||||
return newSpliterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return elements.size() - currentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return ORDERED | SIZED | SUBSIZED | NONNULL;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.baeldung.spliterator;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Executor {
|
||||
|
||||
public static int countAutors(Stream<Author> stream) {
|
||||
RelatedAuthorCounter wordCounter = stream.reduce(new RelatedAuthorCounter(0, true),
|
||||
RelatedAuthorCounter::accumulate, RelatedAuthorCounter::combine);
|
||||
return wordCounter.getCounter();
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package com.baeldung.spliterator;
|
||||
|
||||
public class RelatedAuthorCounter {
|
||||
private final int counter;
|
||||
private final boolean isRelated;
|
||||
|
||||
public RelatedAuthorCounter(int counter, boolean isRelated) {
|
||||
this.counter = counter;
|
||||
this.isRelated = isRelated;
|
||||
}
|
||||
|
||||
public RelatedAuthorCounter accumulate(Author author) {
|
||||
if (author.getRelatedArticleId() == 0) {
|
||||
return isRelated ? this : new RelatedAuthorCounter(counter, true);
|
||||
} else {
|
||||
return isRelated ? new RelatedAuthorCounter(counter + 1, false) : this;
|
||||
}
|
||||
}
|
||||
|
||||
public RelatedAuthorCounter combine(RelatedAuthorCounter RelatedAuthorCounter) {
|
||||
return new RelatedAuthorCounter(counter + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated);
|
||||
}
|
||||
|
||||
public int getCounter() {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
package com.baeldung.spliterator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RelatedAuthorSpliterator implements Spliterator<Author> {
|
||||
private final List<Author> list;
|
||||
AtomicInteger current = new AtomicInteger();
|
||||
|
||||
public RelatedAuthorSpliterator(List<Author> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super Author> action) {
|
||||
|
||||
action.accept(list.get(current.getAndIncrement()));
|
||||
return current.get() < list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<Author> trySplit() {
|
||||
int currentSize = list.size() - current.get();
|
||||
if (currentSize < 10) {
|
||||
return null;
|
||||
}
|
||||
for (int splitPos = currentSize / 2 + current.intValue(); splitPos < list.size(); splitPos++) {
|
||||
if (list.get(splitPos).getRelatedArticleId() == 0) {
|
||||
Spliterator<Author> spliterator = new RelatedAuthorSpliterator(list.subList(current.get(), splitPos));
|
||||
current.set(splitPos);
|
||||
return spliterator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return list.size() - current.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return CONCURRENT;
|
||||
}
|
||||
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
package com.baeldung.streamreduce.application;
|
||||
|
||||
import com.baeldung.streamreduce.entities.User;
|
||||
import com.baeldung.streamreduce.utilities.NumberUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
|
||||
int result1 = numbers.stream().reduce(0, (a, b) -> a + b);
|
||||
System.out.println(result1);
|
||||
|
||||
int result2 = numbers.stream().reduce(0, Integer::sum);
|
||||
System.out.println(result2);
|
||||
|
||||
List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
|
||||
String result3 = letters.stream().reduce("", (a, b) -> a + b);
|
||||
System.out.println(result3);
|
||||
|
||||
String result4 = letters.stream().reduce("", String::concat);
|
||||
System.out.println(result4);
|
||||
|
||||
String result5 = letters.stream().reduce("", (a, b) -> a.toUpperCase() + b.toUpperCase());
|
||||
System.out.println(result5);
|
||||
|
||||
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
|
||||
int result6 = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
|
||||
System.out.println(result6);
|
||||
|
||||
String result7 = letters.parallelStream().reduce("", String::concat);
|
||||
System.out.println(result7);
|
||||
|
||||
int result8 = users.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
|
||||
System.out.println(result8);
|
||||
|
||||
List<User> userList = new ArrayList<>();
|
||||
for (int i = 0; i <= 1000000; i++) {
|
||||
userList.add(new User("John" + i, i));
|
||||
}
|
||||
|
||||
long t1 = System.currentTimeMillis();
|
||||
int result9 = userList.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
|
||||
long t2 = System.currentTimeMillis();
|
||||
System.out.println(result9);
|
||||
System.out.println("Sequential stream time: " + (t2 - t1) + "ms");
|
||||
|
||||
long t3 = System.currentTimeMillis();
|
||||
int result10 = userList.parallelStream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
|
||||
long t4 = System.currentTimeMillis();
|
||||
System.out.println(result10);
|
||||
System.out.println("Parallel stream time: " + (t4 - t3) + "ms");
|
||||
|
||||
int result11 = NumberUtils.divideListElements(numbers, 1);
|
||||
System.out.println(result11);
|
||||
|
||||
int result12 = NumberUtils.divideListElementsWithExtractedTryCatchBlock(numbers, 0);
|
||||
System.out.println(result12);
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package com.baeldung.streamreduce.entities;
|
||||
|
||||
public class Review {
|
||||
|
||||
int points;
|
||||
String review;
|
||||
|
||||
public Review(int points, String review) {
|
||||
this.points = points;
|
||||
this.review = review;
|
||||
}
|
||||
|
||||
public int getPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
public void setPoints(int points) {
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
public String getReview() {
|
||||
return review;
|
||||
}
|
||||
|
||||
public void setReview(String review) {
|
||||
this.review = review;
|
||||
}
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
package com.baeldung.streamreduce.utilities;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public abstract class NumberUtils {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(NumberUtils.class.getName());
|
||||
|
||||
public static int divideListElements(List<Integer> values, Integer divider) {
|
||||
return values.stream()
|
||||
.reduce(0, (a, b) -> {
|
||||
try {
|
||||
return a / divider + b / divider;
|
||||
} catch (ArithmeticException e) {
|
||||
LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
public static int divideListElementsWithExtractedTryCatchBlock(List<Integer> values, int divider) {
|
||||
return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
|
||||
}
|
||||
|
||||
public static int divideListElementsWithApplyFunctionMethod(List<Integer> values, int divider) {
|
||||
BiFunction<Integer, Integer, Integer> division = (a, b) -> a / b;
|
||||
return values.stream().reduce(0, (a, b) -> applyFunction(division, a, divider) + applyFunction(division, b, divider));
|
||||
}
|
||||
|
||||
private static int divide(int value, int factor) {
|
||||
int result = 0;
|
||||
try {
|
||||
result = value / factor;
|
||||
} catch (ArithmeticException e) {
|
||||
LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int applyFunction(BiFunction<Integer, Integer, Integer> function, int a, int b) {
|
||||
try {
|
||||
return function.apply(a, b);
|
||||
}
|
||||
catch(Exception e) {
|
||||
LOGGER.log(Level.INFO, "Exception occurred!");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+38
-12
@@ -6,10 +6,10 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -18,22 +18,50 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class ExecutorUnitTest {
|
||||
Article article;
|
||||
Stream<Author> stream;
|
||||
Spliterator<Author> spliterator;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
article = new Article(Arrays.asList(new Author("Ahmad", 0), new Author("Eugen", 0), new Author("Alice", 1), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0),
|
||||
new Author("Alice", 1), new Author("Mike", 0), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1), new Author("Mike", 0), new Author("Alice", 1),
|
||||
new Author("Mike", 0), new Author("Michał", 0), new Author("Loredana", 1)), 0);
|
||||
|
||||
spliterator = new RelatedAuthorSpliterator(article.getListOfAuthors());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAstreamOfAuthors_whenProcessedInParallelWithCustomSpliterator_coubtProducessRightOutput() {
|
||||
Stream<Author> stream2 = StreamSupport.stream(spliterator, true);
|
||||
assertThat(Executor.countAutors(stream2.parallel())).isEqualTo(9);
|
||||
public void givenAStreamOfIntegers_whenProcessedSequentialCustomSpliterator_countProducesRightOutput() {
|
||||
List<Integer> numbers = new ArrayList<>();
|
||||
numbers.add(1);
|
||||
numbers.add(2);
|
||||
numbers.add(3);
|
||||
numbers.add(4);
|
||||
numbers.add(5);
|
||||
|
||||
CustomSpliterator customSpliterator = new CustomSpliterator(numbers);
|
||||
|
||||
AtomicInteger sum = new AtomicInteger();
|
||||
|
||||
customSpliterator.forEachRemaining(sum::addAndGet);
|
||||
assertThat(sum.get()).isEqualTo(15);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAStreamOfIntegers_whenProcessedInParallelWithCustomSpliterator_countProducesRightOutput() {
|
||||
List<Integer> numbers = new ArrayList<>();
|
||||
numbers.add(1);
|
||||
numbers.add(2);
|
||||
numbers.add(3);
|
||||
numbers.add(4);
|
||||
numbers.add(5);
|
||||
|
||||
CustomSpliterator customSpliterator = new CustomSpliterator(numbers);
|
||||
|
||||
// Create a ForkJoinPool for parallel processing
|
||||
ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
|
||||
|
||||
AtomicInteger sum = new AtomicInteger(0);
|
||||
|
||||
// Process elements in parallel using parallelStream
|
||||
forkJoinPool.submit(() -> customSpliterator.forEachRemaining(sum::addAndGet)).join();
|
||||
assertThat(sum.get()).isEqualTo(15);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -43,9 +71,7 @@ public class ExecutorUnitTest {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Spliterator<Article> spliterator = articles.spliterator();
|
||||
while (spliterator.tryAdvance(article -> article.setName(article.getName()
|
||||
.concat("- published by Baeldung"))))
|
||||
;
|
||||
while(spliterator.tryAdvance(article -> article.setName(article.getName().concat("- published by Baeldung"))));
|
||||
|
||||
articles.forEach(article -> assertThat(article.getName()).isEqualTo("Java- published by Baeldung"));
|
||||
}
|
||||
|
||||
@@ -10,3 +10,5 @@ This module contains articles about arrays conversion in Java
|
||||
- [Convert Java Array to Iterable](https://www.baeldung.com/java-array-convert-to-iterable)
|
||||
- [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)
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.array.conversions;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class ByteToCharArrayUnitTest {
|
||||
public static byte[] byteArray = {65, 66, 67, 68};
|
||||
public static char[] expected = {'A', 'B', 'C', 'D'};
|
||||
|
||||
@Test
|
||||
public void givenByteArray_WhenUsingStandardCharsets_thenConvertToCharArray() {
|
||||
char[] charArray = new String(byteArray, StandardCharsets.UTF_8).toCharArray();
|
||||
assertArrayEquals(expected, charArray);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenByteArray_WhenUsingSUsingStreams_thenConvertToCharArray() throws IOException {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArray);
|
||||
InputStreamReader reader = new InputStreamReader(inputStream);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
int data;
|
||||
while ((data = reader.read()) != -1) {
|
||||
char ch = (char) data;
|
||||
outputStream.write(ch);
|
||||
}
|
||||
char[] charArray = outputStream.toString().toCharArray();
|
||||
assertArrayEquals(expected, charArray);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenByteArray_WhenUsingCharBuffer_thenConvertToCharArray() {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
|
||||
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
|
||||
char[] charArray = new char[charBuffer.remaining()];
|
||||
charBuffer.get(charArray);
|
||||
assertArrayEquals(expected, charArray);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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-arrays-operations-advanced-2</artifactId>
|
||||
<name>core-java-arrays-operations-advanced-2</name>
|
||||
|
||||
@@ -58,4 +58,8 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.arraycompare;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ArraysCompareUnitTest {
|
||||
|
||||
@Test
|
||||
void givenSameContents_whenCompare_thenCorrect() {
|
||||
String[] array1 = new String[] { "A", "B", "C" };
|
||||
String[] array2 = new String[] { "A", "B", "C" };
|
||||
|
||||
assertThat(Arrays.compare(array1, array2)).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenDifferentContents_whenCompare_thenDifferent() {
|
||||
String[] array1 = new String[] { "A", "B", "C" };
|
||||
String[] array2 = new String[] { "A", "C", "B", "D" };
|
||||
|
||||
assertThat(Arrays.compare(array1, array2)).isLessThan(0);
|
||||
assertThat(Arrays.compare(array2, array1)).isGreaterThan(0);
|
||||
assertThat(Arrays.compare(array1, null)).isGreaterThan(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
## Core Java Arrays - Basic Operations
|
||||
|
||||
This module contains articles about Java array fundamentals. They assume no previous background knowledge on working with arrays.
|
||||
|
||||
### Relevant Articles:
|
||||
- [Arrays mismatch() Method in Java](https://www.baeldung.com/java-arrays-mismatch)
|
||||
@@ -0,0 +1,16 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-arrays-operations-basic-2</artifactId>
|
||||
<name>core-java-arrays-operations-basic-2</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
package com.baeldung.array.mismatch;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ArrayMismatchUnitTest {
|
||||
|
||||
@Test
|
||||
void givenTwoArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() {
|
||||
int[] firstArray = {1, 2, 3, 4, 5};
|
||||
int[] secondArray = {1, 2, 3, 5, 8};
|
||||
assertEquals(3, Arrays.mismatch(firstArray, secondArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoIdenticalArrays_whenMismatch_thenMinusOne() {
|
||||
int[] firstArray = {1, 2, 3, 4, 5};
|
||||
int[] secondArray = {1, 2, 3, 4, 5};
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, secondArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFirstArrayIsAPrefixOfTheSecond_whenMismatch_thenFirstArrayLength() {
|
||||
int[] firstArray = {1, 2, 3, 4, 5};
|
||||
int[] secondArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assertEquals(firstArray.length, Arrays.mismatch(firstArray, secondArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNoCommonPrefix_whenMismatch_thenZero() {
|
||||
int[] firstArray = {1, 2, 3, 4, 5};
|
||||
int[] secondArray = {9, 8, 7};
|
||||
assertEquals(0, Arrays.mismatch(firstArray, secondArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAtLeastANullArray_whenMismatch_thenThrowsNullPointerException() {
|
||||
int[] firstArray = null;
|
||||
int[] secondArray = {1, 2, 3, 4, 5};
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, firstArray));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, firstArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenExactlyOneAnEmptyArray_whenMismatch_thenZero() {
|
||||
int[] firstArray = {};
|
||||
int[] secondArray = {1, 2, 3};
|
||||
assertEquals(0, Arrays.mismatch(firstArray, secondArray));
|
||||
assertEquals(0, Arrays.mismatch(secondArray, firstArray));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoEmptyArrays_whenMismatch_thenMinusOne() {
|
||||
assertEquals(-1, Arrays.mismatch(new int[] {}, new int[] {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoSubArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() {
|
||||
int[] firstArray = {1, 2, 3, 4, 5};
|
||||
int[] secondArray = {0, 1, 2, 3, 5, 8};
|
||||
assertEquals(3, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoIdenticalSubArrays_whenMismatch_thenMinusOne() {
|
||||
int[] firstArray = {0, 0, 1, 2};
|
||||
int[] secondArray = {0, 1, 2, 3, 4};
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, 2, 4, secondArray, 1, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFirstSubArrayIsAPrefixOfTheSecond_whenMismatch_thenFirstArrayLength() {
|
||||
int[] firstArray = {2, 3, 4, 5, 4, 3, 2};
|
||||
int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assertEquals(4, Arrays.mismatch(firstArray, 0, 4, secondArray, 2, 9));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNoCommonPrefixForSubArrays_whenMismatch_thenZero() {
|
||||
int[] firstArray = {0, 0, 0, 0, 0};
|
||||
int[] secondArray = {9, 8, 7, 6, 5};
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 1, 2, secondArray, 1, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAtLeastANullSubArray_whenMismatch_thenThrowsNullPointerException() {
|
||||
int[] firstArray = null;
|
||||
int[] secondArray = {1, 2, 3, 4, 5};
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, secondArray, 0, 1));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, firstArray, 0, 1));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, firstArray, 0, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenExactlyOneEmptySubArray_whenMismatch_thenZero() {
|
||||
int[] firstArray = {1};
|
||||
int[] secondArray = {1, 2, 3};
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 0, 0, secondArray, 0, 2));
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 0, 1, secondArray, 2, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoEmptySubArrays_whenMismatch_thenMinusOne() {
|
||||
int[] firstArray = {1};
|
||||
int[] secondArray = {1, 2, 3};
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, 0, 0, secondArray, 2, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenToIndexGreaterThanFromIndex_whenMismatch_thenThrowsIllegalArgumentException() {
|
||||
int[] firstArray = {2, 3, 4, 5, 4, 3, 2};
|
||||
int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 4, 2, secondArray, 0, 6));
|
||||
assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 6, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIllegalIndexes_whenMismatch_thenThrowsArrayIndexOutOfBoundsException() {
|
||||
int[] firstArray = {2, 3, 4, 5, 4, 3, 2};
|
||||
int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, -1, 2, secondArray, 0, 6));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 0, 8, secondArray, 0, 6));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, -5, 0));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 11, 12));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoStringArraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() {
|
||||
String[] firstArray = {"one", "two", "three"};
|
||||
String[] secondArray = {"ONE", "TWO", "FOUR"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(2, Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoIdenticalStringArraysForTheComparator_whenMismatch_thenMinusOne() {
|
||||
String[] firstArray = {"one", "two", "three"};
|
||||
String[] secondArray = {"ONE", "TWO", "THREE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFirstStringArrayIsAPrefixOfTheSecondForTheComparator_whenMismatch_thenFirstArrayLength() {
|
||||
String[] firstArray = {"one", "two", "three"};
|
||||
String[] secondArray = {"ONE", "TWO", "THREE", "FOUR", "FIVE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(firstArray.length, Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNoCommonPrefixForTheComparator_whenMismatch_thenZero() {
|
||||
String[] firstArray = {"one", "two", "three"};
|
||||
String[] secondArray = {"six", "seven", "eight"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(0, Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAtLeastANullArrayOrNullComparator_whenMismatch_thenThrowsNullPointerException() {
|
||||
String[] firstArray = null;
|
||||
String[] secondArray = {"one"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, firstArray, comparator));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, secondArray, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenExactlyOneAnEmptyArrayAndAComparator_whenMismatch_thenZero() {
|
||||
String[] firstArray = {};
|
||||
String[] secondArray = {"one"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(0, Arrays.mismatch(firstArray, secondArray, comparator));
|
||||
assertEquals(0, Arrays.mismatch(secondArray, firstArray, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoEmptyStringArraysForTheComparator_whenMismatch_thenMinusOne() {
|
||||
assertEquals(-1, Arrays.mismatch(new String[] {}, new String[] {}, String.CASE_INSENSITIVE_ORDER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoStringSubarraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() {
|
||||
String[] firstArray = {"one", "two", "three", "four"};
|
||||
String[] secondArray = {"ZERO", "ONE", "TWO", "FOUR", "EIGHT", "SIXTEEN"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(2, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 3, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoIdenticalStringSubArraysForTheComparator_whenMismatch_thenMinusOne() {
|
||||
String[] firstArray = {"zero", "zero", "one", "two"};
|
||||
String[] secondArray = {"zero", "one", "two", "three", "four"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, 2, 4, secondArray, 1, 3, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenFirstSubArrayIsAPrefixOfTheSecondForTheComparator_whenMismatch_thenFirstArrayLength() {
|
||||
String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"};
|
||||
String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(4, Arrays.mismatch(firstArray, 0, 4, secondArray, 2, 9, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNoCommonPrefixForSubArraysForTheComparator_whenMismatch_thenZero() {
|
||||
String[] firstArray = {"zero", "one"};
|
||||
String[] secondArray = {"TEN", "ELEVEN", "TWELVE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 1, 2, secondArray, 1, 2, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenAtLeastANullSubArrayOrNullComparator_whenMismatch_thenThrowsNullPointerException() {
|
||||
String[] firstArray = null;
|
||||
String[] secondArray = {"ONE", "TWO", "THREE", "FOUR", "FIVE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, secondArray, 0, 1, comparator));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, firstArray, 0, 1, comparator));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, 0, 1, firstArray, 0, 1, comparator));
|
||||
assertThrows(NullPointerException.class, () -> Arrays.mismatch(secondArray, 0, 1, secondArray, 0, 1, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenExactlyOneEmptySubArrayAndAComparator_whenMismatch_thenZero() {
|
||||
String[] firstArray = {"one"};
|
||||
String[] secondArray = {"ONE", "TWO", "THREE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 0, 0, secondArray, 0, 2, comparator));
|
||||
assertEquals(0, Arrays.mismatch(firstArray, 0, 1, secondArray, 2, 2, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenTwoEmptySubArraysAndAComparator_whenMismatch_thenMinusOne() {
|
||||
String[] firstArray = {"one"};
|
||||
String[] secondArray = {"ONE", "TWO", "THREE"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertEquals(-1, Arrays.mismatch(firstArray, 0, 0, secondArray, 2, 2, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenToIndexGreaterThanFromIndexAndAComparator_whenMismatch_thenThrowsIllegalArgumentException() {
|
||||
String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"};
|
||||
String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 4, 2, secondArray, 0, 6, comparator));
|
||||
assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 6, 0, comparator));
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIllegalIndexesAndAComparator_whenMismatch_thenThrowsArrayIndexOutOfBoundsException() {
|
||||
String[] firstArray = {"two", "three", "four", "five", "four", "three", "two"};
|
||||
String[] secondArray = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "EIGHT", "NINE", "TEN"};
|
||||
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, -1, 2, secondArray, 0, 6, comparator));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 0, 8, secondArray, 0, 6, comparator));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, -5, 0, comparator));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, 2, 3, secondArray, 11, 12, comparator));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
<properties>
|
||||
<commons-lang.version>2.2</commons-lang.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -7,4 +7,8 @@
|
||||
- [Creating Custom Iterator in Java](https://www.baeldung.com/java-creating-custom-iterator)
|
||||
- [Difference Between Arrays.sort() and Collections.sort()](https://www.baeldung.com/java-arrays-collections-sort-methods)
|
||||
- [Skipping the First Iteration in Java](https://www.baeldung.com/java-skip-first-iteration)
|
||||
- [Remove Elements From a Queue Using Loop](https://www.baeldung.com/java-remove-elements-queue)
|
||||
- [Intro to Vector Class in Java](https://www.baeldung.com/java-vector-guide)
|
||||
- [HashSet toArray() Method in Java](https://www.baeldung.com/java-hashset-toarray)
|
||||
- [Time Complexity of Java Collections Sort in Java](https://www.baeldung.com/java-time-complexity-collections-sort)
|
||||
- More articles: [[<-- prev]](/core-java-modules/core-java-collections-4)
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.collectionssortcomplexity;
|
||||
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
@Fork(value = 1, warmups = 1)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 5, time = 1)
|
||||
public class CollectionsSortTimeComplexityJMH {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
org.openjdk.jmh.Main.main(args);
|
||||
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void measureCollectionsSortBestCase(BestCaseBenchmarkState state) {
|
||||
List<Integer> sortedList = new ArrayList<>(state.sortedList);
|
||||
Collections.sort(sortedList);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void measureCollectionsSortAverageWorstCase(AverageWorstCaseBenchmarkState state) {
|
||||
List<Integer> unsortedList = new ArrayList<>(state.unsortedList);
|
||||
Collections.sort(unsortedList);
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class BestCaseBenchmarkState {
|
||||
List<Integer> sortedList;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setUp() {
|
||||
sortedList = new ArrayList<>();
|
||||
for (int i = 1; i <= 1000000; i++) {
|
||||
sortedList.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public static class AverageWorstCaseBenchmarkState {
|
||||
List<Integer> unsortedList;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setUp() {
|
||||
unsortedList = new ArrayList<>();
|
||||
for (int i = 1000000; i > 0; i--) {
|
||||
unsortedList.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baeldung.collectionssortcomplexity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CollectionsSortTimeComplexityMain {
|
||||
// O(n log n) Time Complexity Example
|
||||
public static void worstAndAverageCasesTimeComplexity() {
|
||||
Integer[] sortedArray = {20, 21, 22, 23, 24, 25, 26, 17, 28, 29, 30, 31, 18, 19, 32, 33, 34, 27, 35};
|
||||
List<Integer> list = Arrays.asList(sortedArray);
|
||||
Collections.shuffle(list);
|
||||
long startTime = System.nanoTime();
|
||||
Collections.sort(list);
|
||||
long endTime = System.nanoTime();
|
||||
System.out.println("Execution Time for O(n log n): " + (endTime - startTime) + " nanoseconds");
|
||||
}
|
||||
|
||||
// O(n) Time Complexity Example
|
||||
public static void bestCaseTimeComplexity() {
|
||||
Integer[] sortedArray = {19, 22, 19, 22, 24, 25, 17, 11, 22, 23, 28, 23, 0, 1, 12, 9, 13, 27, 15};
|
||||
List<Integer> list = Arrays.asList(sortedArray);
|
||||
long startTime = System.nanoTime();
|
||||
Collections.sort(list);
|
||||
long endTime = System.nanoTime();
|
||||
System.out.println("Execution Time for O(n): " + (endTime - startTime) + " nanoseconds");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
worstAndAverageCasesTimeComplexity();
|
||||
bestCaseTimeComplexity();
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.removequeueelements;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class RemoveQueueElementsUnitTest {
|
||||
@Test
|
||||
public void givenQueueWithEvenAndOddNumbers_whenRemovingEvenNumbers_thenOddNumbersRemain() {
|
||||
Queue<Integer> queue = new LinkedList<>();
|
||||
Queue<Integer> oddElementsQueue = new LinkedList<>();
|
||||
queue.add(1);
|
||||
queue.add(2);
|
||||
queue.add(3);
|
||||
queue.add(4);
|
||||
queue.add(5);
|
||||
|
||||
while (queue.peek() != null) {
|
||||
int element = queue.remove();
|
||||
if (element % 2 != 0) {
|
||||
oddElementsQueue.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(3, oddElementsQueue.size());
|
||||
assertTrue(oddElementsQueue.contains(1));
|
||||
assertTrue(oddElementsQueue.contains(3));
|
||||
assertTrue(oddElementsQueue.contains(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringQueue_whenRemovingStringsThatStartWithA_thenStringElementsRemain() {
|
||||
Queue<String> queue = new LinkedList<>();
|
||||
Queue<String> stringElementsQueue = new LinkedList<>();
|
||||
queue.add("Apple");
|
||||
queue.add("Banana");
|
||||
queue.add("Orange");
|
||||
queue.add("Grape");
|
||||
queue.add("Mango");
|
||||
|
||||
|
||||
while (queue.peek() != null) {
|
||||
String element = queue.remove();
|
||||
if (!element.startsWith("A")) {
|
||||
stringElementsQueue.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(4, stringElementsQueue.size());
|
||||
assertTrue(stringElementsQueue.contains("Banana"));
|
||||
assertTrue(stringElementsQueue.contains("Orange"));
|
||||
assertTrue(stringElementsQueue.contains("Grape"));
|
||||
assertTrue(stringElementsQueue.contains("Mango"));
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.baeldung.vectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class VectorOperationsUnitTest {
|
||||
|
||||
private static Vector<String> getVector() {
|
||||
Vector<String> vector = new Vector<String>();
|
||||
vector.add("Today");
|
||||
vector.add("is");
|
||||
vector.add("a");
|
||||
vector.add("great");
|
||||
vector.add("day!");
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenAddElementsUsingAddMethod_thenElementsGetAddedAtEnd() {
|
||||
Vector<String> vector = getVector();
|
||||
vector.add("Hello");
|
||||
assertEquals(6, vector.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenUpdateElementAtIndex_thenElementAtIndexGetsUpdated() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
assertEquals("great", vector.get(3));
|
||||
vector.set(3, "good");
|
||||
assertEquals("good", vector.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenRemoveAnElement_thenElementGetsRemovedFromTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
|
||||
// remove a specific element
|
||||
vector.remove("a");
|
||||
assertEquals(4, vector.size());
|
||||
|
||||
// remove at specific index
|
||||
vector.remove(2);
|
||||
assertEquals("day!", vector.get(2));
|
||||
assertEquals(3, vector.size());
|
||||
|
||||
assertEquals(false, vector.remove("SomethingThatDoesn'tExist"));
|
||||
}
|
||||
|
||||
@Test(expected = ArrayIndexOutOfBoundsException.class)
|
||||
public void givenAVector_whenIndexIsBeyondRange_thenRemoveMethodThrowsArrayIndexOutOfBoundsException() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
vector.remove(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenGetElementWithinARange_thenGetMethodGetsAnElementFromTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
String fourthElement = vector.get(3);
|
||||
assertEquals("great", fourthElement);
|
||||
}
|
||||
|
||||
@Test(expected = ArrayIndexOutOfBoundsException.class)
|
||||
public void givenAVector_whenGetElementBeyondARange_thenGetMethodThrowsArrayIndexOutOfBoundsException() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
vector.get(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAVector_whenAddElementFromACollection_thenAllElementsGetAdeddToTheVector() {
|
||||
Vector<String> vector = getVector();
|
||||
assertEquals(5, vector.size());
|
||||
ArrayList<String> words = new ArrayList<>(Arrays.asList("Baeldung", "is", "cool!"));
|
||||
vector.addAll(words);
|
||||
assertEquals(8, vector.size());
|
||||
assertEquals("cool!", vector.get(7));
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.toarraymethod;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ConvertingHashSetToArrayUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenStringHashSet_whenConvertedToArray_thenArrayContainsStringElements() {
|
||||
HashSet<String> stringSet = new HashSet<>();
|
||||
stringSet.add("Apple");
|
||||
stringSet.add("Banana");
|
||||
stringSet.add("Cherry");
|
||||
|
||||
// Convert the HashSet of Strings to an array of Strings
|
||||
String[] stringArray = stringSet.toArray(new String[0]);
|
||||
|
||||
// Test that the array is of the correct length
|
||||
assertEquals(3, stringArray.length);
|
||||
|
||||
for (String str : stringArray) {
|
||||
assertTrue(stringSet.contains(str));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenIntegerHashSet_whenConvertedToArray_thenArrayContainsIntegerElements() {
|
||||
HashSet<Integer> integerSet = new HashSet<>();
|
||||
integerSet.add(5);
|
||||
integerSet.add(10);
|
||||
integerSet.add(15);
|
||||
|
||||
// Convert the HashSet of Integers to an array of Integers
|
||||
Integer[] integerArray = integerSet.toArray(new Integer[0]);
|
||||
|
||||
// Test that the array is of the correct length
|
||||
assertEquals(3, integerArray.length);
|
||||
|
||||
for (Integer num : integerArray) {
|
||||
assertTrue(integerSet.contains(num));
|
||||
}
|
||||
|
||||
assertTrue(integerSet.contains(5));
|
||||
assertTrue(integerSet.contains(10));
|
||||
assertTrue(integerSet.contains(15));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
<project
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-collections-array-list-2</artifactId>
|
||||
<name>core-java-collections-array-list-2</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -24,7 +24,7 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<properties>
|
||||
<maven-compiler-plugin.source>17</maven-compiler-plugin.source>
|
||||
<maven-compiler-plugin.target>17</maven-compiler-plugin.target>
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
<properties>
|
||||
<vavr.version>0.10.3</vavr.version>
|
||||
<java.version>11</java.version>
|
||||
<modelmapper.version>3.1.1</modelmapper.version>
|
||||
<modelmapper.version>3.2.0</modelmapper.version>
|
||||
</properties>
|
||||
</project>
|
||||
+14
-25
@@ -1,8 +1,9 @@
|
||||
package com.baeldung.modelmapper;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.TypeMap;
|
||||
import org.modelmapper.TypeToken;
|
||||
@@ -10,11 +11,10 @@ import org.modelmapper.TypeToken;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
|
||||
/**
|
||||
* This class has test methods of mapping Integer to Character list,
|
||||
@@ -22,12 +22,12 @@ import static org.junit.Assert.assertThat;
|
||||
*
|
||||
* @author Sasa Milenkovic
|
||||
*/
|
||||
public class UsersListMappingUnitTest {
|
||||
class UsersListMappingUnitTest {
|
||||
|
||||
private ModelMapper modelMapper;
|
||||
private List<User> users;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
|
||||
modelMapper = new ModelMapper();
|
||||
@@ -35,18 +35,16 @@ public class UsersListMappingUnitTest {
|
||||
TypeMap<UserList, UserListDTO> typeMap = modelMapper.createTypeMap(UserList.class, UserListDTO.class);
|
||||
|
||||
typeMap.addMappings(mapper -> mapper.using(new UsersListConverter())
|
||||
.map(UserList::getUsers, UserListDTO::setUsernames));
|
||||
.map(UserList::getUsers, UserListDTO::setUsernames));
|
||||
|
||||
users = new ArrayList();
|
||||
users = new ArrayList<>();
|
||||
users.add(new User("b100", "user1", "user1@baeldung.com", "111-222", "USER"));
|
||||
users.add(new User("b101", "user2", "user2@baeldung.com", "111-333", "USER"));
|
||||
users.add(new User("b102", "user3", "user3@baeldung.com", "111-444", "ADMIN"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenInteger_thenMapToCharacter() {
|
||||
|
||||
void whenInteger_thenMapToCharacter() {
|
||||
List<Integer> integers = new ArrayList<Integer>();
|
||||
|
||||
integers.add(1);
|
||||
@@ -57,36 +55,27 @@ public class UsersListMappingUnitTest {
|
||||
}.getType());
|
||||
|
||||
assertThat(characters, hasItems('1', '2', '3'));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsersList_whenUseGenericType_thenMapToUserDTO() {
|
||||
|
||||
void givenUsersList_whenUseGenericType_thenMapToUserDTO() {
|
||||
// Mapping lists using custom (generic) type mapping
|
||||
|
||||
List<UserDTO> userDtoList = MapperUtil.mapList(users, UserDTO.class);
|
||||
|
||||
assertThat(userDtoList, Matchers.<UserDTO>hasItem(
|
||||
Matchers.both(hasProperty("userId", equalTo("b100")))
|
||||
.and(hasProperty("email", equalTo("user1@baeldung.com")))
|
||||
.and(hasProperty("username", equalTo("user1")))));
|
||||
|
||||
|
||||
assertThat(userDtoList, Matchers.<UserDTO> hasItem(Matchers.both(hasProperty("userId", equalTo("b100")))
|
||||
.and(hasProperty("email", equalTo("user1@baeldung.com")))
|
||||
.and(hasProperty("username", equalTo("user1")))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsersList_whenUseConverter_thenMapToUsernames() {
|
||||
|
||||
void givenUsersList_whenUseConverter_thenMapToUsernames() {
|
||||
// Mapping lists using property mapping and converter
|
||||
|
||||
UserList userList = new UserList();
|
||||
userList.setUsers(users);
|
||||
UserListDTO dtos = new UserListDTO();
|
||||
modelMapper.map(userList, dtos);
|
||||
|
||||
assertThat(dtos.getUsernames(), hasItems("user1", "user2", "user3"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,3 +4,4 @@ This module contains articles about conversions among Collection types in Java.
|
||||
|
||||
### Relevant Articles:
|
||||
- [Converting HashMap Values to an ArrayList in Java](https://www.baeldung.com/java-hashmap-arraylist)
|
||||
- [Joining a List<String> in Java With Commas and “and”](https://www.baeldung.com/java-string-concatenation-natural-language)
|
||||
|
||||
+12
-1
@@ -71,4 +71,15 @@ public class ListOfListsUnitTest {
|
||||
assertThat(listOfLists.get(2)).containsExactly("Slack", "Zoom", "Microsoft Teams", "Telegram");
|
||||
printListOfLists(listOfLists);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenListOfLists_whenGettingSizeOfSubListsAndSizeOfElements_thenGetExpectedResults() throws URISyntaxException, IOException {
|
||||
List<List<String>> listOfLists = getListOfListsFromCsv();
|
||||
// size of inner lists
|
||||
assertThat(listOfLists).hasSize(3);
|
||||
|
||||
// size of all elements in subLists
|
||||
int totalElements = listOfLists.stream().mapToInt(List::size).sum();
|
||||
assertThat(totalElements).isEqualTo(12);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -66,9 +66,8 @@
|
||||
<properties>
|
||||
<jmh.version>1.21</jmh.version>
|
||||
<commons-lang.version>2.2</commons-lang.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.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>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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-list-6</artifactId>
|
||||
<name>core-java-collections-list-6</name>
|
||||
@@ -12,4 +12,5 @@
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
||||
@@ -9,3 +9,4 @@
|
||||
- [Converting String or String Array to Map in Java](https://www.baeldung.com/java-convert-string-to-map)
|
||||
- [Remove Duplicate Values From HashMap in Java](https://www.baeldung.com/java-hashmap-delete-duplicates)
|
||||
- [Sorting Java Map in Descending Order](https://www.baeldung.com/java-sort-map-descending)
|
||||
- [Convert HashMap.toString() to HashMap in Java](https://www.baeldung.com/hashmap-from-tostring)
|
||||
|
||||
@@ -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>
|
||||
@@ -40,7 +37,7 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -51,4 +48,8 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.version>5.2.5.RELEASE</spring.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -1 +1,10 @@
|
||||
## Relevant Articles
|
||||
## Relevant Articles:
|
||||
- [Difference Between putIfAbsent() and computeIfAbsent() in Java’s Map](https://www.baeldung.com/java-map-putifabsent-computeifabsent)
|
||||
- [How to Write and Read a File with a Java HashMap](https://www.baeldung.com/how-to-write-and-read-a-file-with-a-java-hashmap/)
|
||||
- [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-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)
|
||||
|
||||
@@ -13,66 +13,56 @@
|
||||
<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.12.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>1.36</version>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.9</version>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20230227</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>${csv.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.2-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
<version>1.37</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-generator-annprocess</artifactId>
|
||||
<version>1.37</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
--add-opens java.base/java.util=ALL-UNNAMED
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<csv.version>1.5</csv.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.baeldung.map;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class HashMapWithMaxSizeLimit<K, V> extends HashMap<K, V> {
|
||||
private int maxSize = -1;
|
||||
|
||||
public HashMapWithMaxSizeLimit() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HashMapWithMaxSizeLimit(int maxSize) {
|
||||
super();
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if (this.maxSize == -1 || this.containsKey(key) || this.size() < this.maxSize) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
throw new RuntimeException("Max size exceeded!");
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.baeldung.map.incrementmapkey;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BenchmarkMapMethods {
|
||||
public static void main(String[] args) {
|
||||
BenchmarkMapMethods bmm = new BenchmarkMapMethods();
|
||||
Map<String, Long> map = new HashMap<>();
|
||||
map.put("Guava", bmm.benchMarkGuavaMap());
|
||||
map.put("ContainsKey", bmm.benchContainsKeyMap());
|
||||
map.put("MergeMethod", bmm.benchMarkMergeMethod());
|
||||
map.put("ComputeMethod", bmm.benchMarComputeMethod());
|
||||
map.put("GetOrDefault", bmm.benchMarkGetOrDefaultMethod());
|
||||
}
|
||||
|
||||
private long benchMarkGuavaMap() {
|
||||
long startTime = System.nanoTime();
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingAtomicMap(getString());
|
||||
long endTime = System.nanoTime();
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
private long benchContainsKeyMap() {
|
||||
long startTime = System.nanoTime();
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingContainsKey(getString());
|
||||
long endTime = System.nanoTime();
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
private long benchMarComputeMethod() {
|
||||
long startTime = System.nanoTime();
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingCompute(getString());
|
||||
long endTime = System.nanoTime();
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
private long benchMarkMergeMethod() {
|
||||
long startTime = System.nanoTime();
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingMerge(getString());
|
||||
long endTime = System.nanoTime();
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
private long benchMarkGetOrDefaultMethod() {
|
||||
long startTime = System.nanoTime();
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingGetOrDefault(getString());
|
||||
long endTime = System.nanoTime();
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
private String getString() {
|
||||
return
|
||||
"Once upon a time in a quaint village nestled between rolling hills and whispering forests, there lived a solitary storyteller named Elias. Elias was known for spinning tales that transported listeners to magical realms and awakened forgotten dreams.\n"
|
||||
+ "\n"
|
||||
+ "His favorite spot was beneath an ancient oak tree, its sprawling branches offering shade to those who sought refuge from the bustle of daily life. Villagers of all ages would gather around Elias, their faces illuminated by the warmth of his stories.\n"
|
||||
+ "\n" + "One evening, as dusk painted the sky in hues of orange and purple, a curious young girl named Lily approached Elias. Her eyes sparkled with wonder as she asked for a tale unlike any other.\n" + "\n"
|
||||
+ "Elias smiled, sensing her thirst for adventure, and began a story about a forgotten kingdom veiled by mist, guarded by mystical creatures and enchanted by ancient spells. With each word, the air grew thick with anticipation, and the listeners were transported into a world where magic danced on the edges of reality.\n"
|
||||
+ "\n" + "As Elias weaved the story, Lily's imagination took flight. She envisioned herself as a brave warrior, wielding a shimmering sword against dark forces, her heart fueled by courage and kindness.\n" + "\n"
|
||||
+ "The night wore on, but the spell of the tale held everyone captive. The villagers laughed, gasped, and held their breaths, journeying alongside the characters through trials and triumphs.\n" + "\n"
|
||||
+ "As the final words lingered in the air, a sense of enchantment settled upon the listeners. They thanked Elias for the gift of his storytelling, each carrying a piece of the magical kingdom within their hearts.\n" + "\n"
|
||||
+ "Lily, inspired by the story, vowed to cherish the spirit of adventure and kindness in her own life. With a newfound spark in her eyes, she bid Elias goodnight, already dreaming of the countless adventures awaiting her.\n" + "\n"
|
||||
+ "Under the star-studded sky, Elias remained beneath the ancient oak, his heart aglow with the joy of sharing tales that ignited imagination and inspired dreams. And as the night embraced the village, whispers of the enchanted kingdom lingered in the breeze, promising endless possibilities to those who dared to believe.";
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.baeldung.map.incrementmapkey;
|
||||
|
||||
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.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public class BenchmarkMapMethodsJMH {
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(value = 1, warmups = 1)
|
||||
public void benchMarkGuavaMap() {
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingAtomicMap(getString());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(value = 1, warmups = 1)
|
||||
public void benchContainsKeyMap() {
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingContainsKey(getString());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(value = 1, warmups = 1)
|
||||
public void benchMarkComputeMethod() {
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingCompute(getString());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Fork(value = 1, warmups = 1)
|
||||
public void benchMarkMergeMethod() {
|
||||
IncrementMapValueWays im = new IncrementMapValueWays();
|
||||
im.charFrequencyUsingMerge(getString());
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
org.openjdk.jmh.Main.main(args);
|
||||
}
|
||||
|
||||
private String getString() {
|
||||
return
|
||||
"Once upon a time in a quaint village nestled between rolling hills and whispering forests, there lived a solitary storyteller named Elias. Elias was known for spinning tales that transported listeners to magical realms and awakened forgotten dreams.\n"
|
||||
+ "\n"
|
||||
+ "His favorite spot was beneath an ancient oak tree, its sprawling branches offering shade to those who sought refuge from the bustle of daily life. Villagers of all ages would gather around Elias, their faces illuminated by the warmth of his stories.\n"
|
||||
+ "\n" + "One evening, as dusk painted the sky in hues of orange and purple, a curious young girl named Lily approached Elias. Her eyes sparkled with wonder as she asked for a tale unlike any other.\n" + "\n"
|
||||
+ "Elias smiled, sensing her thirst for adventure, and began a story about a forgotten kingdom veiled by mist, guarded by mystical creatures and enchanted by ancient spells. With each word, the air grew thick with anticipation, and the listeners were transported into a world where magic danced on the edges of reality.\n"
|
||||
+ "\n" + "As Elias weaved the story, Lily's imagination took flight. She envisioned herself as a brave warrior, wielding a shimmering sword against dark forces, her heart fueled by courage and kindness.\n" + "\n"
|
||||
+ "The night wore on, but the spell of the tale held everyone captive. The villagers laughed, gasped, and held their breaths, journeying alongside the characters through trials and triumphs.\n" + "\n"
|
||||
+ "As the final words lingered in the air, a sense of enchantment settled upon the listeners. They thanked Elias for the gift of his storytelling, each carrying a piece of the magical kingdom within their hearts.\n" + "\n"
|
||||
+ "Lily, inspired by the story, vowed to cherish the spirit of adventure and kindness in her own life. With a newfound spark in her eyes, she bid Elias goodnight, already dreaming of the countless adventures awaiting her.\n" + "\n"
|
||||
+ "Under the star-studded sky, Elias remained beneath the ancient oak, his heart aglow with the joy of sharing tales that ignited imagination and inspired dreams. And as the night embraced the village, whispers of the enchanted kingdom lingered in the breeze, promising endless possibilities to those who dared to believe.";
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.baeldung.map.incrementmapkey;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.google.common.util.concurrent.AtomicLongMap;
|
||||
|
||||
public class IncrementMapValueWays {
|
||||
|
||||
public Map<Character, Integer> charFrequencyUsingContainsKey(String sentence) {
|
||||
Map<Character, Integer> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
int count = 0;
|
||||
if (charMap.containsKey(sentence.charAt(c))) {
|
||||
count = charMap.get(sentence.charAt(c));
|
||||
}
|
||||
charMap.put(sentence.charAt(c), count + 1);
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, Integer> charFrequencyUsingGetOrDefault(String sentence) {
|
||||
Map<Character, Integer> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.put(sentence.charAt(c), charMap.getOrDefault(sentence.charAt(c), 0) + 1);
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, Integer> charFrequencyUsingMerge(String sentence) {
|
||||
Map<Character, Integer> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.merge(sentence.charAt(c), 1, Integer::sum);
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, Integer> charFrequencyUsingCompute(String sentence) {
|
||||
Map<Character, Integer> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.compute(sentence.charAt(c), (key, value) -> (value == null) ? 1 : value + 1);
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, Long> charFrequencyUsingAtomicMap(String sentence) {
|
||||
AtomicLongMap<Character> map = AtomicLongMap.create();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
map.getAndIncrement(sentence.charAt(c));
|
||||
}
|
||||
return map.asMap();
|
||||
}
|
||||
|
||||
public Map<Character, Integer> charFrequencyWithConcurrentMap(String sentence, Map<Character, Integer> charMap) {
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.compute(sentence.charAt(c), (key, value) -> (value == null) ? 1 : value + 1);
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, AtomicInteger> charFrequencyWithGetAndIncrement(String sentence) {
|
||||
Map<Character, AtomicInteger> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.putIfAbsent(sentence.charAt(c), new AtomicInteger(0));
|
||||
charMap.get(sentence.charAt(c))
|
||||
.incrementAndGet();
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
|
||||
public Map<Character, AtomicInteger> charFrequencyWithGetAndIncrementComputeIfAbsent(String sentence) {
|
||||
Map<Character, AtomicInteger> charMap = new HashMap<>();
|
||||
for (int c = 0; c < sentence.length(); c++) {
|
||||
charMap.computeIfAbsent(sentence.charAt(c), k -> new AtomicInteger(0))
|
||||
.incrementAndGet();
|
||||
}
|
||||
return charMap;
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.map.readandwritefile;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Student implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
/** Default constructor for JSON serialization */
|
||||
public Student() {
|
||||
|
||||
}
|
||||
|
||||
public Student(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Student student = (Student) o;
|
||||
return Objects.equals(firstName, student.firstName) && Objects.equals(lastName, student.lastName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.baeldung.map;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LimitMaxSizeHashMapByCustomHashMapUnitTest {
|
||||
|
||||
private final int MAX_SIZE = 4;
|
||||
private HashMapWithMaxSizeLimit<Integer, String> hashMapWithMaxSizeLimit;
|
||||
|
||||
@Test
|
||||
void givenCustomHashMapObject_whenThereIsNoLimit_thenDoesNotThrowException() {
|
||||
hashMapWithMaxSizeLimit = new HashMapWithMaxSizeLimit<Integer, String>();
|
||||
assertDoesNotThrow(() -> {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
hashMapWithMaxSizeLimit.put(i, i + "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenCustomHashMapObject_whenLimitNotReached_thenDoesNotThrowException() {
|
||||
hashMapWithMaxSizeLimit = new HashMapWithMaxSizeLimit<Integer, String>(MAX_SIZE);
|
||||
assertDoesNotThrow(() -> {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hashMapWithMaxSizeLimit.put(i, i + "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenCustomHashMapObject_whenReplacingValueWhenLimitIsReached_thenDoesNotThrowException() {
|
||||
hashMapWithMaxSizeLimit = new HashMapWithMaxSizeLimit<Integer, String>(MAX_SIZE);
|
||||
assertDoesNotThrow(() -> {
|
||||
hashMapWithMaxSizeLimit.put(1, "One");
|
||||
hashMapWithMaxSizeLimit.put(2, "Two");
|
||||
hashMapWithMaxSizeLimit.put(3, "Three");
|
||||
hashMapWithMaxSizeLimit.put(4, "Four");
|
||||
hashMapWithMaxSizeLimit.put(4, "4");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenCustomHashMapObject_whenLimitExceeded_thenThrowsException() {
|
||||
hashMapWithMaxSizeLimit = new HashMapWithMaxSizeLimit<Integer, String>(MAX_SIZE);
|
||||
Exception exception = assertThrows(RuntimeException.class, () -> {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
hashMapWithMaxSizeLimit.put(i, i + "");
|
||||
}
|
||||
});
|
||||
|
||||
String messageThrownWhenSizeExceedsLimit = "Max size exceeded!";
|
||||
String actualMessage = exception.getMessage();
|
||||
assertTrue(actualMessage.equals(messageThrownWhenSizeExceedsLimit));
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LimitMaxSizeHashMapByLinkedHashMapUnitTest {
|
||||
|
||||
@Test
|
||||
void givenLinkedHashMapObject_whenAddingNewEntry_thenEldestEntryIsRemoved() {
|
||||
final int MAX_SIZE = 4;
|
||||
LinkedHashMap<Integer, String> linkedHashMap;
|
||||
linkedHashMap = new LinkedHashMap<Integer, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
|
||||
return size() > MAX_SIZE;
|
||||
}
|
||||
};
|
||||
linkedHashMap.put(1, "One");
|
||||
linkedHashMap.put(2, "Two");
|
||||
linkedHashMap.put(3, "Three");
|
||||
linkedHashMap.put(4, "Four");
|
||||
linkedHashMap.put(5, "Five");
|
||||
String[] expectedArrayAfterFive = { "Two", "Three", "Four", "Five" };
|
||||
assertArrayEquals(expectedArrayAfterFive, linkedHashMap.values()
|
||||
.toArray());
|
||||
linkedHashMap.put(6, "Six");
|
||||
String[] expectedArrayAfterSix = { "Three", "Four", "Five", "Six" };
|
||||
assertArrayEquals(expectedArrayAfterSix, linkedHashMap.values()
|
||||
.toArray());
|
||||
}
|
||||
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package com.baeldung.map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class Player {
|
||||
private String name;
|
||||
private Integer score = 0;
|
||||
|
||||
public Player(String name, Integer score) {
|
||||
this.name = name;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player player = (Player) o;
|
||||
|
||||
if (!Objects.equals(name, player.name)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(score, player.score);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (score != null ? score.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
}
|
||||
|
||||
public class LinkedHashMapSortByValueUnitTest {
|
||||
private static LinkedHashMap<String, Integer> MY_MAP = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
MY_MAP.put("key a", 4);
|
||||
MY_MAP.put("key b", 1);
|
||||
MY_MAP.put("key c", 3);
|
||||
MY_MAP.put("key d", 2);
|
||||
MY_MAP.put("key e", 5);
|
||||
}
|
||||
|
||||
private static LinkedHashMap<String, Integer> EXPECTED_MY_MAP = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
EXPECTED_MY_MAP.put("key b", 1);
|
||||
EXPECTED_MY_MAP.put("key d", 2);
|
||||
EXPECTED_MY_MAP.put("key c", 3);
|
||||
EXPECTED_MY_MAP.put("key a", 4);
|
||||
EXPECTED_MY_MAP.put("key e", 5);
|
||||
}
|
||||
|
||||
private static final LinkedHashMap<String, Player> PLAYERS = new LinkedHashMap<>();
|
||||
static {
|
||||
PLAYERS.put("player a", new Player("Eric", 9));
|
||||
PLAYERS.put("player b", new Player("Kai", 7));
|
||||
PLAYERS.put("player c", new Player("Amanda", 20));
|
||||
PLAYERS.put("player d", new Player("Kevin", 4));
|
||||
}
|
||||
|
||||
private static final LinkedHashMap<String, Player> EXPECTED_PLAYERS = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
EXPECTED_PLAYERS.put("player d", new Player("Kevin", 4));
|
||||
EXPECTED_PLAYERS.put("player b", new Player("Kai", 7));
|
||||
EXPECTED_PLAYERS.put("player a", new Player("Eric", 9));
|
||||
EXPECTED_PLAYERS.put("player c", new Player("Amanda", 20));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingCollectionSort_thenGetExpectedResult() {
|
||||
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(MY_MAP.entrySet());
|
||||
Collections.sort(entryList, new Comparator<Map.Entry<String, Integer>>() {
|
||||
@Override
|
||||
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
|
||||
return o1.getValue()
|
||||
.compareTo(o2.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Integer> e : entryList) {
|
||||
result.put(e.getKey(), e.getValue());
|
||||
}
|
||||
assertEquals(EXPECTED_MY_MAP, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingEntrycomparingByValueAndFillAMap_thenGetExpectedResult() {
|
||||
LinkedHashMap<String, Integer> result = new LinkedHashMap<>();
|
||||
MY_MAP.entrySet()
|
||||
.stream()
|
||||
.sorted(Map.Entry.comparingByValue())
|
||||
.forEachOrdered(entry -> result.put(entry.getKey(), entry.getValue()));
|
||||
assertEquals(EXPECTED_MY_MAP, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingEntrycomparingByValueAndCollect_thenGetExpectedResult() {
|
||||
LinkedHashMap<String, Integer> result = MY_MAP.entrySet()
|
||||
.stream()
|
||||
.sorted(Map.Entry.comparingByValue())
|
||||
.collect(LinkedHashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll);
|
||||
assertEquals(EXPECTED_MY_MAP, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingEntrycomparingByValueAndComparator_thenGetExpectedResult() {
|
||||
LinkedHashMap<String, Player> result = PLAYERS.entrySet()
|
||||
.stream()
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.comparing(Player::getScore)))
|
||||
.collect(LinkedHashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll);
|
||||
assertEquals(EXPECTED_PLAYERS, result);
|
||||
}
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.baeldung.map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class Magic {
|
||||
public String nullFunc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String strFunc(String input) {
|
||||
return input + ": A nice string";
|
||||
}
|
||||
}
|
||||
|
||||
public class PutIfAbsentVsComputeIfAbsentUnitTest {
|
||||
|
||||
private static final Map<String, String> MY_MAP = new HashMap<>();
|
||||
private Magic magic = new Magic();
|
||||
|
||||
@BeforeEach
|
||||
void resetTheMap() {
|
||||
MY_MAP.clear();
|
||||
MY_MAP.put("Key A", "value A");
|
||||
MY_MAP.put("Key B", "value B");
|
||||
MY_MAP.put("Key C", "value C");
|
||||
MY_MAP.put("Key Null", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingPutIfAbsentWithAbsentKey_thenGetNull() {
|
||||
String putResult = MY_MAP.putIfAbsent("new key1", magic.nullFunc());
|
||||
assertNull(putResult);
|
||||
|
||||
putResult = MY_MAP.putIfAbsent("new key2", magic.strFunc("new key2"));
|
||||
assertNull(putResult);
|
||||
|
||||
putResult = MY_MAP.putIfAbsent("Key Null", magic.strFunc("Key Null"));
|
||||
assertNull(putResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingComputeIfAbsentWithAbsentKey_thenGetExpectedResult() {
|
||||
String computeResult = MY_MAP.computeIfAbsent("new key1", k -> magic.nullFunc());
|
||||
assertNull(computeResult);
|
||||
|
||||
computeResult = MY_MAP.computeIfAbsent("new key2", k -> magic.strFunc(k));
|
||||
assertEquals("new key2: A nice string", computeResult);
|
||||
|
||||
computeResult = MY_MAP.computeIfAbsent("Key Null", k -> magic.strFunc(k));
|
||||
assertEquals("Key Null: A nice string", computeResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingPutIfAbsentWithAbsentKey_thenNullIsPut() {
|
||||
assertEquals(4, MY_MAP.size()); // initial: 4 entries
|
||||
MY_MAP.putIfAbsent("new key", magic.nullFunc());
|
||||
assertEquals(5, MY_MAP.size());
|
||||
assertTrue(MY_MAP.containsKey("new key")); // new entry has been added to the map
|
||||
assertNull(MY_MAP.get("new key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingComputeIfAbsentWithAbsentKey_thenNullIsNotPut() {
|
||||
assertEquals(4, MY_MAP.size()); // initial: 4 entries
|
||||
MY_MAP.computeIfAbsent("new key", k -> magic.nullFunc());
|
||||
assertEquals(4, MY_MAP.size());
|
||||
assertFalse(MY_MAP.containsKey("new key")); // <- no new entry added
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingPutIfAbsent_thenFunctionIsAlwaysCalled() {
|
||||
Magic spyMagic = spy(magic);
|
||||
MY_MAP.putIfAbsent("Key A", spyMagic.strFunc("Key A"));
|
||||
verify(spyMagic, times(1)).strFunc(anyString());
|
||||
|
||||
MY_MAP.putIfAbsent("new key", spyMagic.strFunc("new key"));
|
||||
verify(spyMagic, times(2)).strFunc(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenCallingComputeIfAbsent_thenFunctionIsCalledOnDemand() {
|
||||
Magic spyMagic = spy(magic);
|
||||
MY_MAP.computeIfAbsent("Key A", k -> spyMagic.strFunc(k));
|
||||
verify(spyMagic, never()).strFunc(anyString());
|
||||
|
||||
MY_MAP.computeIfAbsent("new key", k -> spyMagic.strFunc(k));
|
||||
verify(spyMagic, times(1)).strFunc(anyString());
|
||||
}
|
||||
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.map.incrementmapkey;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.baeldung.map.incrementmapkey.IncrementMapValueWays;
|
||||
|
||||
public class IncrementMapValueUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingContainsKey_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, Integer> actualMap = ic.charFrequencyUsingContainsKey(string);
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap, actualMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingGetOrDefault_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, Integer> actualMap = ic.charFrequencyUsingGetOrDefault(string);
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap, actualMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingMapMerge_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, Integer> actualMap = ic.charFrequencyUsingMerge(string);
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap, actualMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingMapCompute_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, Integer> actualMap = ic.charFrequencyUsingCompute(string);
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap, actualMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingGuava_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, Long> actualMap = ic.charFrequencyUsingAtomicMap(string);
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap.keySet(), actualMap.keySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingIncrementAndGet_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, AtomicInteger> actualMap = ic.charFrequencyWithGetAndIncrement(string);
|
||||
Assert.assertEquals(getExpectedMap().keySet(), actualMap.keySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingIncrementAndGetAndComputeIfAbsent_thenReturnFreqMap() {
|
||||
String string = "the quick brown fox jumps over the lazy dog";
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
Map<Character, AtomicInteger> actualMap = ic.charFrequencyWithGetAndIncrementComputeIfAbsent(string);
|
||||
Assert.assertEquals(getExpectedMap().keySet(), actualMap.keySet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_whenUsingConcurrentMapCompute_thenReturnFreqMap() throws InterruptedException {
|
||||
Map<Character, Integer> charMap = new ConcurrentHashMap<>();
|
||||
Thread thread1 = new Thread(() -> {
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
ic.charFrequencyWithConcurrentMap("the quick brown", charMap);
|
||||
});
|
||||
|
||||
Thread thread2 = new Thread(() -> {
|
||||
IncrementMapValueWays ic = new IncrementMapValueWays();
|
||||
ic.charFrequencyWithConcurrentMap(" fox jumps over the lazy dog", charMap);
|
||||
});
|
||||
|
||||
thread1.start();
|
||||
thread2.start();
|
||||
thread1.join();
|
||||
thread2.join();
|
||||
|
||||
Map<Character, Integer> expectedMap = getExpectedMap();
|
||||
Assert.assertEquals(expectedMap, charMap);
|
||||
}
|
||||
|
||||
private Map<Character, Integer> getExpectedMap() {
|
||||
return Stream.of(
|
||||
new Object[][] { { ' ', 8 }, { 'a', 1 }, { 'b', 1 }, { 'c', 1 }, { 'd', 1 }, { 'e', 3 }, { 'f', 1 }, { 'g', 1 }, { 'h', 2 }, { 'i', 1 }, { 'j', 1 }, { 'k', 1 }, { 'l', 1 }, { 'm', 1 }, { 'n', 1 }, { 'o', 4 }, { 'p', 1 }, { 'q', 1 }, { 'r', 2 },
|
||||
{ 's', 1 }, { 't', 2 }, { 'u', 2 }, { 'v', 1 }, { 'w', 1 }, { 'x', 1 }, { 'y', 1 }, { 'z', 1 } })
|
||||
.collect(Collectors.toMap(data -> (Character) data[0], data -> (Integer) data[1]));
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.map.linkedhashmapfirstandlastentry;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
public class GetFirstAndLastEntryFromLinkedHashMapUnitTest {
|
||||
private static final LinkedHashMap<String, String> THE_MAP = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
THE_MAP.put("key one", "a1 b1 c1");
|
||||
THE_MAP.put("key two", "a2 b2 c2");
|
||||
THE_MAP.put("key three", "a3 b3 c3");
|
||||
THE_MAP.put("key four", "a4 b4 c4");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenIteratingEntrySet_thenGetExpectedResult() {
|
||||
Entry<String, String> firstEntry = THE_MAP.entrySet().iterator().next();
|
||||
assertEquals("key one", firstEntry.getKey());
|
||||
assertEquals("a1 b1 c1", firstEntry.getValue());
|
||||
|
||||
Entry<String, String> lastEntry = null;
|
||||
Iterator<Entry<String, String>> it = THE_MAP.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
lastEntry = it.next();
|
||||
}
|
||||
|
||||
assertNotNull(lastEntry);
|
||||
assertEquals("key four", lastEntry.getKey());
|
||||
assertEquals("a4 b4 c4", lastEntry.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConvertingEntriesToArray_thenGetExpectedResult() {
|
||||
|
||||
Entry<String, String>[] theArray = new Entry[THE_MAP.size()];
|
||||
THE_MAP.entrySet().toArray(theArray);
|
||||
|
||||
Entry<String, String> firstEntry = theArray[0];
|
||||
assertEquals("key one", firstEntry.getKey());
|
||||
assertEquals("a1 b1 c1", firstEntry.getValue());
|
||||
|
||||
Entry<String, String> lastEntry = theArray[THE_MAP.size() - 1];
|
||||
assertEquals("key four", lastEntry.getKey());
|
||||
assertEquals("a4 b4 c4", lastEntry.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingStreamAPI_thenGetExpectedResult() {
|
||||
Entry<String, String> firstEntry = THE_MAP.entrySet().stream().findFirst().get();
|
||||
assertEquals("key one", firstEntry.getKey());
|
||||
assertEquals("a1 b1 c1", firstEntry.getValue());
|
||||
|
||||
Entry<String, String> lastEntry = THE_MAP.entrySet().stream().skip(THE_MAP.size() - 1).findFirst().get();
|
||||
|
||||
assertNotNull(lastEntry);
|
||||
assertEquals("key four", lastEntry.getKey());
|
||||
assertEquals("a4 b4 c4", lastEntry.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingReflection_thenGetExpectedResult() throws NoSuchFieldException, IllegalAccessException {
|
||||
Field head = THE_MAP.getClass().getDeclaredField("head");
|
||||
head.setAccessible(true);
|
||||
Entry<String, String> firstEntry = (Entry<String, String>) head.get(THE_MAP);
|
||||
assertEquals("key one", firstEntry.getKey());
|
||||
assertEquals("a1 b1 c1", firstEntry.getValue());
|
||||
|
||||
Field tail = THE_MAP.getClass().getDeclaredField("tail");
|
||||
tail.setAccessible(true);
|
||||
Entry<String, String> lastEntry = (Entry<String, String>) tail.get(THE_MAP);
|
||||
assertEquals("key four", lastEntry.getKey());
|
||||
assertEquals("a4 b4 c4", lastEntry.getValue());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
package com.baeldung.map.readandwritefile;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
|
||||
public class ReadAndWriteFileWithHashMapUnitTest {
|
||||
|
||||
private static final Map<Integer, Student> STUDENT_DATA = new HashMap<>();
|
||||
|
||||
static {
|
||||
STUDENT_DATA.put(1234, new Student("Henry", "Winter"));
|
||||
STUDENT_DATA.put(5678, new Student("Richard", "Papen"));
|
||||
}
|
||||
|
||||
private File file;
|
||||
|
||||
@Before
|
||||
public void createFile() throws IOException {
|
||||
file = File.createTempFile("student", ".data");
|
||||
}
|
||||
|
||||
@After
|
||||
public void deleteFile() {
|
||||
file.delete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenHashMap_whenWrittenAsPropertiesFile_thenReloadedMapIsIdentical() throws IOException {
|
||||
// Given a map containing student data
|
||||
Map<String, String> studentData = new HashMap<>();
|
||||
studentData.put("student.firstName", "Henry");
|
||||
studentData.put("student.lastName", "Winter");
|
||||
|
||||
// When converting to a Properties object and writing to a file
|
||||
Properties props = new Properties();
|
||||
props.putAll(studentData);
|
||||
try (OutputStream output = Files.newOutputStream(file.toPath())) {
|
||||
props.store(output, null);
|
||||
}
|
||||
|
||||
// Then the map resulting from loading the Properties file is identical
|
||||
Properties propsFromFile = new Properties();
|
||||
try (InputStream input = Files.newInputStream(file.toPath())) {
|
||||
propsFromFile.load(input);
|
||||
}
|
||||
|
||||
Map<String, String> studentDataFromProps = propsFromFile.stringPropertyNames()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(key -> key, props::getProperty));
|
||||
assertThat(studentDataFromProps).isEqualTo(studentData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenHashMap_whenSerializedToFile_thenDeserializedMapIsIdentical() throws IOException, ClassNotFoundException {
|
||||
// Given a map containing student data (STUDENT_DATA)
|
||||
|
||||
// When serializing the map to a file
|
||||
try (FileOutputStream fileOutput = new FileOutputStream(file); ObjectOutputStream objectStream = new ObjectOutputStream(fileOutput)) {
|
||||
objectStream.writeObject(STUDENT_DATA);
|
||||
}
|
||||
|
||||
// Then read the file back into a map and check the contents
|
||||
Map<Integer, Student> studentsFromFile;
|
||||
try (FileInputStream fileReader = new FileInputStream(file); ObjectInputStream objectStream = new ObjectInputStream(fileReader)) {
|
||||
studentsFromFile = (HashMap<Integer, Student>) objectStream.readObject();
|
||||
}
|
||||
assertThat(studentsFromFile).isEqualTo(STUDENT_DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenHashMap_whenSerializedToFileWithJackson_thenDeserializedMapIsIdentical() throws IOException {
|
||||
// Given a map containing student data (STUDENT_DATA)
|
||||
|
||||
// When converting to JSON with Jackson and writing to a file
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try (FileOutputStream fileOutput = new FileOutputStream(file)) {
|
||||
mapper.writeValue(fileOutput, STUDENT_DATA);
|
||||
}
|
||||
|
||||
// Then deserialize the file back into a map and check that it's identical
|
||||
Map<Integer, Student> mapFromFile;
|
||||
try (FileInputStream fileInput = new FileInputStream(file)) {
|
||||
// Create a TypeReference so we can deserialize the parameterized type
|
||||
TypeReference<HashMap<Integer, Student>> mapType = new TypeReference<HashMap<Integer, Student>>() {
|
||||
};
|
||||
mapFromFile = mapper.readValue(fileInput, mapType);
|
||||
}
|
||||
assertThat(mapFromFile).isEqualTo(STUDENT_DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenHashMap_whenSerializedToFileWithGson_thenDeserializedMapIsIdentical() throws IOException {
|
||||
// Given a map containing student data (STUDENT_DATA)
|
||||
|
||||
// When converting to JSON using Gson and writing to a file
|
||||
Gson gson = new Gson();
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
gson.toJson(STUDENT_DATA, writer);
|
||||
}
|
||||
|
||||
// Then deserialize the file back into a map and check that it's identical
|
||||
Map<Integer, Student> studentsFromFile;
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
Type mapType = new TypeToken<HashMap<Integer, Student>>() {
|
||||
}.getType();
|
||||
studentsFromFile = gson.fromJson(reader, mapType);
|
||||
}
|
||||
assertThat(studentsFromFile).isEqualTo(STUDENT_DATA);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.baeldung.writehashmaptocsvfile;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class WriteHashmaptoCVSFileUnitTest {
|
||||
public Map<String, String> employeeData;
|
||||
|
||||
public WriteHashmaptoCVSFileUnitTest() {
|
||||
employeeData = new HashMap<>();
|
||||
employeeData.put("Name", "John Doe");
|
||||
employeeData.put("Title", "Software Engineer");
|
||||
employeeData.put("Department", "Engineering");
|
||||
employeeData.put("Salary", "75000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenEmployeeData_whenWriteToCSVUsingFileWriter_thenCSVFileIsCreated() {
|
||||
|
||||
try (FileWriter csvWriter = new FileWriter("employee_data.csv")) {
|
||||
// Write header row
|
||||
csvWriter.append("Name,Title,Department,Salary\n");
|
||||
|
||||
// Write data row
|
||||
csvWriter.append(employeeData.get("Name")).append(",");
|
||||
csvWriter.append(employeeData.get("Title")).append(",");
|
||||
csvWriter.append(employeeData.get("Department")).append(",");
|
||||
csvWriter.append(employeeData.get("Salary")).append("\n");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Ensure the CSV file exists
|
||||
assertTrue(new File("employee_data.csv").exists(), "CSV file does not exist!");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCSVFile_whenWriteToCSVUsingApacheCommons_thenContentsMatchExpected() {
|
||||
|
||||
try (CSVPrinter csvPrinter = new CSVPrinter(new FileWriter("employee_data2.csv"), CSVFormat.DEFAULT)) {
|
||||
// Write header row
|
||||
csvPrinter.printRecord("Name", "Title", "Department", "Salary");
|
||||
|
||||
// Write data row
|
||||
csvPrinter.printRecord(employeeData.get("Name"), employeeData.get("Title"), employeeData.get("Department"), employeeData.get("Salary"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Ensure the CSV file exists
|
||||
assertTrue(new File("employee_data2.csv").exists());
|
||||
}
|
||||
}
|
||||
+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);
|
||||
}
|
||||
}
|
||||
@@ -85,12 +85,12 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<jcabi-aspects.version>0.22.6</jcabi-aspects.version>
|
||||
<aspectjrt.version>1.9.5</aspectjrt.version>
|
||||
<aspectjrt.version>1.9.20.1</aspectjrt.version>
|
||||
<cactoos.version>0.43</cactoos.version>
|
||||
<ea-async.version>1.2.3</ea-async.version>
|
||||
<jcabi-maven-plugin.version>0.14.1</jcabi-maven-plugin.version>
|
||||
<aspectjtools.version>1.9.1</aspectjtools.version>
|
||||
<aspectjweaver.version>1.9.1</aspectjweaver.version>
|
||||
<aspectjtools.version>1.9.20.1</aspectjtools.version>
|
||||
<aspectjweaver.version>1.9.20.1</aspectjweaver.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
### Relevant Articles:
|
||||
- [Why wait() Requires Synchronization?](https://www.baeldung.com/java-wait-necessary-synchronization)
|
||||
- [Working with Exceptions in Java CompletableFuture](https://www.baeldung.com/java-exceptions-completablefuture)
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-concurrency-advanced-5</artifactId>
|
||||
<name>core-java-concurrency-advanced-5</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
<artifactId>core-java-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-concurrency-advanced-5</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.baeldung.callback.completablefuture;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class CompletableFutureCallbackExample {
|
||||
public static void main(String[] args) {
|
||||
CompletableFuture<String> completableFuture = new CompletableFuture<>();
|
||||
Runnable runnable = downloadFile(completableFuture);
|
||||
completableFuture.whenComplete((res, error) -> {
|
||||
if (error != null) {
|
||||
// handle the exception scenario
|
||||
} else if (res != null) {
|
||||
// send data to DB
|
||||
}
|
||||
});
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
|
||||
private static Runnable downloadFile(CompletableFuture<String> completableFuture) {
|
||||
return () -> {
|
||||
try {
|
||||
//logic to download file
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
completableFuture.complete("pic.jpg");
|
||||
};
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.callback.listenablefuture;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
|
||||
public class ListenableFutureCallbackExample {
|
||||
public static void main(String[] args) {
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||
ListeningExecutorService pool = MoreExecutors.listeningDecorator(executorService);
|
||||
ListenableFuture<String> listenableFuture = pool.submit(downloadFile());
|
||||
|
||||
Futures.addCallback(listenableFuture, new FutureCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
// code to push fileName to DB
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
// code to take appropriate action when there is an error
|
||||
}
|
||||
}, executorService);
|
||||
}
|
||||
|
||||
private static Callable<String> downloadFile() {
|
||||
return () -> {
|
||||
// Mimicking the downloading of a file by adding a sleep call
|
||||
Thread.sleep(5000);
|
||||
return "pic.jpg";
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user