diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java index 0bfa347efcf..9a9cf47890d 100644 --- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java +++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java @@ -580,7 +580,7 @@ public static short CONST_SHORT(final int v) { * @param object the {@link Object} to test, may be {@code null} * @param defaultValue the default value to return, may be {@code null} * @return {@code object} if it is not {@code null}, defaultValue otherwise - * TODO Rename to getIfNull in 4.0 + * @deprecated use {@link ObjectUtils#getIfNull(Object, Object)} */ public static <T> T defaultIfNull(final T object, final T defaultValue) { return object != null ? object : defaultValue; @@ -640,6 +640,35 @@ public static <T> T firstNonNull(final T... values) { return Streams.of(values).filter(Objects::nonNull).findFirst().orElse(null); } + /** + * Returns the first non-null value in the collection. If all values are {@code null}, + * or if the collection is {@code null} or empty, {@code null} is returned. + * + * <p>Examples: + * <pre> + * ObjectUtils.firstNonNull(Arrays.asList(null, null)) = null + * ObjectUtils.firstNonNull(Arrays.asList(null, "")) = "" + * ObjectUtils.firstNonNull(Arrays.asList(null, null, "")) = "" + * ObjectUtils.firstNonNull(Arrays.asList(null, "zz")) = "zz" + * ObjectUtils.firstNonNull(Arrays.asList("abc", *)) = "abc" + * ObjectUtils.firstNonNull(Arrays.asList(null, "xyz", *)) = "xyz" + * ObjectUtils.firstNonNull(Arrays.asList(Boolean.TRUE, *)) = Boolean.TRUE + * ObjectUtils.firstNonNull(Collections.emptyList()) = null + * ObjectUtils.firstNonNull(null) = null + * </pre> + * + * @param <T> the type of elements in the collection + * @param values the collection to test, may be {@code null} or empty + * @return the first non-null value in the collection, or {@code null} if no non-null value is found + * @since 3.18.0 + */ + public static <T> T firstNonNull(final Collection<T> values) { + if (Objects.isNull(values) || values.isEmpty()) { + return null; + } + return values.stream().filter(Objects::nonNull).findFirst().orElse(null); + } + /** * Delegates to {@link Object#getClass()} using generics. * @@ -706,7 +735,27 @@ public static <T> T getFirstNonNull(final Supplier<T>... suppliers) { * @since 3.10 */ public static <T> T getIfNull(final T object, final Supplier<T> defaultSupplier) { - return object != null ? object : Suppliers.get(defaultSupplier); + return Objects.nonNull(object) ? object : Suppliers.get(defaultSupplier); + } + + /** + * Returns a default value if the object passed is {@code null}. + * + * <pre> + * ObjectUtils.getIfNull(null, null) = null + * ObjectUtils.getIfNull(null, "") = "" + * ObjectUtils.getIfNull(null, "zz") = "zz" + * ObjectUtils.getIfNull("abc", *) = "abc" + * ObjectUtils.getIfNull(Boolean.TRUE, *) = Boolean.TRUE + * </pre> + * + * @param <T> the type of the object + * @param object the {@link Object} to test, may be {@code null} + * @param defaultValue the default value to return, may be {@code null} + * @return {@code object} if it is not {@code null}, defaultValue otherwise + */ + public static <T> T getIfNull(final T object, final T defaultValue) { + return Objects.nonNull(object) ? object : defaultValue; } /** @@ -965,7 +1014,7 @@ their constant using one of the CONST() utility methods, instead: * @since 3.13.0 */ public static boolean isArray(final Object object) { - return object != null && object.getClass().isArray(); + return Objects.nonNull(object) && object.getClass().isArray(); } /** @@ -1382,7 +1431,7 @@ public static void wait(final Object obj, final Duration duration) throws Interr /** * {@link ObjectUtils} instances should NOT be constructed in * standard programming. Instead, the static methods on the class should - * be used, such as {@code ObjectUtils.defaultIfNull("a","b");}. + * be used, such as {@code ObjectUtils.getIfNull("a","b");}. * * <p>This constructor is public to permit tools that require a JavaBean * instance to operate.</p> diff --git a/src/main/java/org/apache/commons/lang3/builder/Diff.java b/src/main/java/org/apache/commons/lang3/builder/Diff.java index 3208424dc15..ac1bcd82849 100644 --- a/src/main/java/org/apache/commons/lang3/builder/Diff.java +++ b/src/main/java/org/apache/commons/lang3/builder/Diff.java @@ -56,7 +56,7 @@ public abstract class Diff<T> extends Pair<T, T> { */ protected Diff(final String fieldName) { this.fieldName = Objects.requireNonNull(fieldName); - this.type = ObjectUtils.defaultIfNull(TypeUtils.getTypeArguments(getClass(), Diff.class).get(Diff.class.getTypeParameters()[0]), Object.class); + this.type = ObjectUtils.getIfNull(TypeUtils.getTypeArguments(getClass(), Diff.class).get(Diff.class.getTypeParameters()[0]), Object.class); } Diff(final String fieldName, final Type type) { diff --git a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java index 3cdc9c11955..8dbfe6de1ba 100644 --- a/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java +++ b/src/main/java/org/apache/commons/lang3/reflect/TypeUtils.java @@ -236,8 +236,8 @@ private static final class WildcardTypeImpl implements WildcardType { * @param lowerBounds of this type */ private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) { - this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, ArrayUtils.EMPTY_TYPE_ARRAY); - this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, ArrayUtils.EMPTY_TYPE_ARRAY); + this.upperBounds = ObjectUtils.getIfNull(upperBounds, ArrayUtils.EMPTY_TYPE_ARRAY); + this.lowerBounds = ObjectUtils.getIfNull(lowerBounds, ArrayUtils.EMPTY_TYPE_ARRAY); } /** diff --git a/src/main/java/org/apache/commons/lang3/text/FormattableUtils.java b/src/main/java/org/apache/commons/lang3/text/FormattableUtils.java index 0e92a9738fc..c9fcd2a4c1a 100644 --- a/src/main/java/org/apache/commons/lang3/text/FormattableUtils.java +++ b/src/main/java/org/apache/commons/lang3/text/FormattableUtils.java @@ -97,7 +97,7 @@ public static Formatter append(final CharSequence seq, final Formatter formatter "Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision)); final StringBuilder buf = new StringBuilder(seq); if (precision >= 0 && precision < seq.length()) { - final CharSequence actualEllipsis = ObjectUtils.defaultIfNull(ellipsis, StringUtils.EMPTY); + final CharSequence actualEllipsis = ObjectUtils.getIfNull(ellipsis, StringUtils.EMPTY); buf.replace(precision - actualEllipsis.length(), seq.length(), actualEllipsis.toString()); } final boolean leftJustify = (flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY; diff --git a/src/main/java/org/apache/commons/lang3/time/DurationUtils.java b/src/main/java/org/apache/commons/lang3/time/DurationUtils.java index 9172c2c2971..68ffaeb5233 100644 --- a/src/main/java/org/apache/commons/lang3/time/DurationUtils.java +++ b/src/main/java/org/apache/commons/lang3/time/DurationUtils.java @@ -219,7 +219,7 @@ public static int toMillisInt(final Duration duration) { * @return The given duration or {@link Duration#ZERO}. */ public static Duration zeroIfNull(final Duration duration) { - return ObjectUtils.defaultIfNull(duration, Duration.ZERO); + return ObjectUtils.getIfNull(duration, Duration.ZERO); } /** diff --git a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java index 28b3fa79e51..013c9bdbb8c 100644 --- a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java @@ -423,6 +423,9 @@ public void testConstructor() { assertFalse(Modifier.isFinal(ObjectUtils.class.getModifiers())); } + /** + * @deprecated + */ @Test public void testDefaultIfNull() { final Object o = FOO; @@ -444,6 +447,27 @@ public void testDefaultIfNull() { assertEquals(1, callsCounter.getValue()); } + @Test + public void testGetIfNull() { + final Object o = FOO; + final Object dflt = BAR; + assertSame(dflt, ObjectUtils.getIfNull(null, dflt), "dflt was not returned when o was null"); + assertSame(o, ObjectUtils.getIfNull(o, dflt), "dflt was returned when o was not null"); + assertSame(dflt, ObjectUtils.getIfNull(null, () -> dflt), "dflt was not returned when o was null"); + assertSame(o, ObjectUtils.getIfNull(o, () -> dflt), "dflt was returned when o was not null"); + assertSame(o, ObjectUtils.getIfNull(FOO, () -> dflt), "dflt was returned when o was not null"); + assertSame(o, ObjectUtils.getIfNull("foo", () -> dflt), "dflt was returned when o was not null"); + final MutableInt callsCounter = new MutableInt(0); + final Supplier<Object> countingDefaultSupplier = () -> { + callsCounter.increment(); + return dflt; + }; + ObjectUtils.getIfNull(o, countingDefaultSupplier); + assertEquals(0, callsCounter.getValue()); + ObjectUtils.getIfNull(null, countingDefaultSupplier); + assertEquals(1, callsCounter.getValue()); + } + @Test public void testEquals() { assertTrue(ObjectUtils.equals(null, null), "ObjectUtils.equals(null, null) returned false"); @@ -454,7 +478,7 @@ public void testEquals() { } @Test - public void testFirstNonNull() { + public void testFirstNonNullArray() { assertEquals("", ObjectUtils.firstNonNull(null, "")); final String firstNonNullGenerics = ObjectUtils.firstNonNull(null, null, "123", "456"); assertEquals("123", firstNonNullGenerics); @@ -471,6 +495,21 @@ public void testFirstNonNull() { assertNull(ObjectUtils.firstNonNull((Object[]) null)); } + @Test + void testFirstNonNullCollection() { + // Test with a collection containing nulls and non-null values + assertEquals("123", ObjectUtils.firstNonNull(Arrays.asList(null, null, "123", "456"))); + assertEquals("", ObjectUtils.firstNonNull(Collections.singletonList(""))); + assertEquals("123", ObjectUtils.firstNonNull(Arrays.asList("123", null, "456", null))); + assertSame(Boolean.TRUE, ObjectUtils.firstNonNull(Collections.singletonList(Boolean.TRUE))); + + // Test with an empty collection (should return null) + assertNull(ObjectUtils.firstNonNull(Collections.emptyList())); + + // Test with a collection containing only nulls (should return null) + assertNull(ObjectUtils.firstNonNull(Arrays.asList(null, null))); + } + @Test public void testGetClass() { final String[] newArray = ArrayUtils.EMPTY_STRING_ARRAY; diff --git a/src/test/java/org/apache/commons/lang3/function/Objects.java b/src/test/java/org/apache/commons/lang3/function/Objects.java index f07a0edbd9b..3d605201dc3 100644 --- a/src/test/java/org/apache/commons/lang3/function/Objects.java +++ b/src/test/java/org/apache/commons/lang3/function/Objects.java @@ -52,7 +52,7 @@ * * This class is somewhat redundant with regards to {@link ObjectUtils}. * For example, {@link #requireNonNull(Object, Object)} is almost equivalent - * with {@link ObjectUtils#defaultIfNull(Object, Object)}. However, it isn't + * with {@link ObjectUtils#getIfNull(Object, Object)}. However, it isn't * quite the same, because the latter can, in fact, return null. The former * can't, and the Java compiler confirms this.(An alternative to redundancy * would have been to change the {@code ObjectUtils} class. However, that