From 3cab3898f4cd8495cf7e6183d0ffceaaca68acb3 Mon Sep 17 00:00:00 2001 From: Bindul Bhowmik Date: Mon, 28 Dec 2020 00:37:41 -0700 Subject: [PATCH 1/4] [LANG-1634] Add ObjectUtils #applyIfNonNull and #applyFirstNonNull Utility methods that take a java.util.function.Consumer and possibly null value(s). The consumer is invoked if the value is not null or with the first non-null value, respectively. --- .../org/apache/commons/lang3/ObjectUtils.java | 57 +++++++++++++++++++ .../apache/commons/lang3/ObjectUtilsTest.java | 36 ++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java index 8461ee9b167..940845ed900 100644 --- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java +++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; import java.util.TreeSet; +import java.util.function.Consumer; import java.util.function.Supplier; import org.apache.commons.lang3.exception.CloneFailedException; @@ -226,6 +227,62 @@ public static boolean anyNotNull(final Object... values) { return firstNonNull(values) != null; } + /** + *

+ * Invokes the given {@code consumer's} {@link Consumer#accept(Object)} with the first {@code non-null} value from + * {@code objects}. If all the values are null, the consumer is not invoked. + *

+ * + *

+ * The caller is responsible for thread-safety and exception handling of consumer. + *

+ * + *
+     * ObjectUtils.applyIfNonNull(bean::setValue, null)                 - setValue not invoked
+     * ObjectUtils.applyIfNonNull(bean::setValue, null, "abc", "def")   - setValue invoked with "abc"
+     * ObjectUtils.applyIfNonNull(v -> bean.setValue(v), "abc")      - setValue invoked with "abc"
+     * 
+ * + * @param the type of the object + * @param objects the values to test, may be {@code null} or empty + * @param consumer the consumer operation to invoke with the first non-null {@code objects}. + * @see #firstNonNull(Object...) + * @see #applyIfNonNull(Consumer, Object) + * @since 3.12 + */ + @SafeVarargs + public static void applyFirstNonNull(final Consumer consumer, final T... objects) { + applyIfNonNull(consumer, firstNonNull(objects)); + } + + /** + *

+ * Invokes the given {@code consumer's} {@link Consumer#accept(Object)} with the {@code object} if it is + * {@code non-null}, otherwise the consumer is not invoked. + *

+ * + *

+ * The caller is responsible for thread-safety and exception handling of consumer. + *

+ * + *
+     * ObjectUtils.applyIfNonNull(bean::setValue, null)             - setValue not invoked
+     * ObjectUtils.applyIfNonNull(bean::setValue, "abc")            - setValue invoked with "abc"
+     * ObjectUtils.applyIfNonNull(v -> bean.setValue(v), "abc")  - setValue invoked with "abc"
+     * 
+ * + * @param the type of the object + * @param object the {@code Object} to test, may be {@code null} + * @param consumer the consumer operation to invoke with {@code object} if it is {@code non-null} + * @see #applyFirstNonNull(Consumer, Object...) + * @since 3.12 + */ + public static void applyIfNonNull(final Consumer consumer, final T object) { + if (object != null) { + consumer.accept(object); + } + } + // cloning //----------------------------------------------------------------------- /** diff --git a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java index 3efafe70ab6..7a997917dfc 100644 --- a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java @@ -245,6 +245,33 @@ public void testEquals() { assertTrue(ObjectUtils.equals(FOO, FOO), "ObjectUtils.equals(\"foo\", \"foo\") returned false"); } + @Test + public void testApplyIfNonNull() { + final ApplyIfNonNullBean bean = new ApplyIfNonNullBean(); + bean.setValue(FOO); + + ObjectUtils.applyIfNonNull(bean::setValue, null); + assertEquals(FOO, bean.getValue()); + + ObjectUtils.applyIfNonNull(bean::setValue, BAR); + assertEquals(BAR, bean.getValue()); + + ObjectUtils.applyIfNonNull(v -> bean.setValue(v), FOO); + assertEquals(FOO, bean.getValue()); + } + + @Test + public void testApplyFirstNonNull() { + final ApplyIfNonNullBean bean = new ApplyIfNonNullBean(); + bean.setValue(FOO); + + ObjectUtils.applyFirstNonNull(bean::setValue, null, null, null); + assertEquals(FOO, bean.getValue()); + + ObjectUtils.applyFirstNonNull(bean::setValue, null, null, BAR, FOO, null); + assertEquals(BAR, bean.getValue()); + } + @Test public void testNotEqual() { assertFalse(ObjectUtils.notEqual(null, null), "ObjectUtils.notEqual(null, null) returned false"); @@ -764,4 +791,13 @@ public int compare(final CharSequence o1, final CharSequence o2) { } + static final class ApplyIfNonNullBean { + private String value; + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + } } From 15d0642385adbc6542fca87f4626876375160ae3 Mon Sep 17 00:00:00 2001 From: Bindul Bhowmik Date: Mon, 28 Dec 2020 14:39:56 -0700 Subject: [PATCH 2/4] Correct method name in Javadoc. --- src/main/java/org/apache/commons/lang3/ObjectUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java index 940845ed900..c4d30274f92 100644 --- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java +++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java @@ -238,9 +238,9 @@ public static boolean anyNotNull(final Object... values) { *

* *
-     * ObjectUtils.applyIfNonNull(bean::setValue, null)                 - setValue not invoked
-     * ObjectUtils.applyIfNonNull(bean::setValue, null, "abc", "def")   - setValue invoked with "abc"
-     * ObjectUtils.applyIfNonNull(v -> bean.setValue(v), "abc")      - setValue invoked with "abc"
+     * ObjectUtils.applyFirstNonNull(bean::setValue, null)                 - setValue not invoked
+     * ObjectUtils.applyFirstNonNull(bean::setValue, null, "abc", "def")   - setValue invoked with "abc"
+     * ObjectUtils.applyFirstNonNull(v -> bean.setValue(v), "abc")      - setValue invoked with "abc"
      * 
* * @param the type of the object From 25f5effcdf4d3f9127febd2e5b0eabb710a17f01 Mon Sep 17 00:00:00 2001 From: Bindul Bhowmik Date: Tue, 29 Dec 2020 13:29:20 -0700 Subject: [PATCH 3/4] Changes for review comments on PR apache/commons-lang#684 - Changed method names from applyIfNonNull -> acceptIfNonNull; and applyFirstNonNull -> acceptFirstNonNull - Changed parameter order --- .../org/apache/commons/lang3/ObjectUtils.java | 31 ++++++++++--------- .../apache/commons/lang3/ObjectUtilsTest.java | 21 +++++++------ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ObjectUtils.java b/src/main/java/org/apache/commons/lang3/ObjectUtils.java index c4d30274f92..a5028507907 100644 --- a/src/main/java/org/apache/commons/lang3/ObjectUtils.java +++ b/src/main/java/org/apache/commons/lang3/ObjectUtils.java @@ -229,8 +229,9 @@ public static boolean anyNotNull(final Object... values) { /** *

- * Invokes the given {@code consumer's} {@link Consumer#accept(Object)} with the first {@code non-null} value from - * {@code objects}. If all the values are null, the consumer is not invoked. + * Calls the given {@code consumer's} {@link Consumer#accept(Object)} method with the first {@code non-null} value + * from {@code objects}. If all the values are null, the consumer is not invoked. This is equivalent to the call + * {@code ObjectUtils.acceptIfNonNull(ObjectUtils.firstNonNull(objects), consumer)} *

* *

@@ -238,27 +239,27 @@ public static boolean anyNotNull(final Object... values) { *

* *
-     * ObjectUtils.applyFirstNonNull(bean::setValue, null)                 - setValue not invoked
-     * ObjectUtils.applyFirstNonNull(bean::setValue, null, "abc", "def")   - setValue invoked with "abc"
-     * ObjectUtils.applyFirstNonNull(v -> bean.setValue(v), "abc")      - setValue invoked with "abc"
+     * ObjectUtils.acceptFirstNonNull(bean::setValue, null)                 - setValue not invoked
+     * ObjectUtils.acceptFirstNonNull(bean::setValue, null, "abc", "def")   - setValue invoked with "abc"
+     * ObjectUtils.acceptFirstNonNull(v -> bean.setValue(v), "abc")      - setValue invoked with "abc"
      * 
* * @param the type of the object * @param objects the values to test, may be {@code null} or empty * @param consumer the consumer operation to invoke with the first non-null {@code objects}. * @see #firstNonNull(Object...) - * @see #applyIfNonNull(Consumer, Object) + * @see #acceptIfNonNull(Object, Consumer) * @since 3.12 */ @SafeVarargs - public static void applyFirstNonNull(final Consumer consumer, final T... objects) { - applyIfNonNull(consumer, firstNonNull(objects)); + public static void acceptFirstNonNull(final Consumer consumer, final T... objects) { + acceptIfNonNull(firstNonNull(objects), consumer); } /** *

- * Invokes the given {@code consumer's} {@link Consumer#accept(Object)} with the {@code object} if it is - * {@code non-null}, otherwise the consumer is not invoked. + * Calls the given {@code consumer's} {@link Consumer#accept(Object)} method with the {@code object} if it is + * {@code non-null}. *

* *

@@ -266,18 +267,18 @@ public static void applyFirstNonNull(final Consumer consumer, final T... *

* *
-     * ObjectUtils.applyIfNonNull(bean::setValue, null)             - setValue not invoked
-     * ObjectUtils.applyIfNonNull(bean::setValue, "abc")            - setValue invoked with "abc"
-     * ObjectUtils.applyIfNonNull(v -> bean.setValue(v), "abc")  - setValue invoked with "abc"
+     * ObjectUtils.acceptIfNonNull(null, bean::setValue)             - setValue not invoked
+     * ObjectUtils.acceptIfNonNull("abc", bean::setValue)            - setValue invoked with "abc"
+     * ObjectUtils.acceptIfNonNull("abc", v -> bean.setValue(v))  - setValue invoked with "abc"
      * 
* * @param the type of the object * @param object the {@code Object} to test, may be {@code null} * @param consumer the consumer operation to invoke with {@code object} if it is {@code non-null} - * @see #applyFirstNonNull(Consumer, Object...) + * @see #acceptFirstNonNull(Consumer, Object...) * @since 3.12 */ - public static void applyIfNonNull(final Consumer consumer, final T object) { + public static void acceptIfNonNull(final T object, final Consumer consumer) { if (object != null) { consumer.accept(object); } diff --git a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java index 7a997917dfc..11eb563dcf7 100644 --- a/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ObjectUtilsTest.java @@ -40,6 +40,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Supplier; @@ -246,30 +247,30 @@ public void testEquals() { } @Test - public void testApplyIfNonNull() { + public void testAcceptFirstNonNull() { final ApplyIfNonNullBean bean = new ApplyIfNonNullBean(); bean.setValue(FOO); - ObjectUtils.applyIfNonNull(bean::setValue, null); + ObjectUtils.acceptFirstNonNull(bean::setValue, null, null, null); assertEquals(FOO, bean.getValue()); - ObjectUtils.applyIfNonNull(bean::setValue, BAR); + ObjectUtils.acceptFirstNonNull(bean::setValue, null, null, BAR, FOO, null); assertEquals(BAR, bean.getValue()); - - ObjectUtils.applyIfNonNull(v -> bean.setValue(v), FOO); - assertEquals(FOO, bean.getValue()); } @Test - public void testApplyFirstNonNull() { + public void testAcceptIfNonNull() { final ApplyIfNonNullBean bean = new ApplyIfNonNullBean(); bean.setValue(FOO); - ObjectUtils.applyFirstNonNull(bean::setValue, null, null, null); + ObjectUtils.acceptIfNonNull(null, bean::setValue); assertEquals(FOO, bean.getValue()); - ObjectUtils.applyFirstNonNull(bean::setValue, null, null, BAR, FOO, null); + ObjectUtils.acceptIfNonNull(BAR, bean::setValue); assertEquals(BAR, bean.getValue()); + + ObjectUtils.acceptIfNonNull(FOO, v -> bean.setValue(v)); + assertEquals(FOO, bean.getValue()); } @Test @@ -797,7 +798,7 @@ public String getValue() { return value; } public void setValue(String value) { - this.value = value; + this.value = Objects.requireNonNull(value, "value"); } } } From adf1e04fb5d614ce6417ce166a90246162f8de60 Mon Sep 17 00:00:00 2001 From: Bindul Bhowmik Date: Tue, 29 Dec 2020 13:31:59 -0700 Subject: [PATCH 4/4] Eat your own dog food for LANG-1634 Update a few existing classes to use ObjectUtils#acceptIfNonNull(Object, Consumer) --- .../org/apache/commons/lang3/StringUtils.java | 20 +++++-------------- .../builder/ReflectionToStringBuilder.java | 5 ++--- .../lang3/concurrent/BasicThreadFactory.java | 13 ++++-------- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java index 478139e37a7..f0874c267ac 100644 --- a/src/main/java/org/apache/commons/lang3/StringUtils.java +++ b/src/main/java/org/apache/commons/lang3/StringUtils.java @@ -4391,16 +4391,12 @@ public static String join(final Iterator iterator, final char separator) { // two or more elements final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small - if (first != null) { - buf.append(first); - } + ObjectUtils.acceptIfNonNull(first, buf::append); while (iterator.hasNext()) { buf.append(separator); final Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } + ObjectUtils.acceptIfNonNull(obj, buf::append); } return buf.toString(); @@ -4435,18 +4431,12 @@ public static String join(final Iterator iterator, final String separator) { // two or more elements final StringBuilder buf = new StringBuilder(STRING_BUILDER_SIZE); // Java default is 16, probably too small - if (first != null) { - buf.append(first); - } + ObjectUtils.acceptIfNonNull(first, buf::append); while (iterator.hasNext()) { - if (separator != null) { - buf.append(separator); - } + ObjectUtils.acceptIfNonNull(separator, buf::append); final Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } + ObjectUtils.acceptIfNonNull(obj, buf::append); } return buf.toString(); } diff --git a/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java b/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java index 63ad959d181..c34829a17f5 100644 --- a/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java +++ b/src/main/java/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java @@ -29,6 +29,7 @@ import org.apache.commons.lang3.ArraySorter; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.Validate; /** @@ -413,9 +414,7 @@ static String[] toNoNullStringArray(final Collection collection) { static String[] toNoNullStringArray(final Object[] array) { final List list = new ArrayList<>(array.length); for (final Object e : array) { - if (e != null) { - list.add(e.toString()); - } + ObjectUtils.acceptIfNonNull(e, o -> list.add(e.toString())); } return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY); } diff --git a/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java b/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java index 631f2e4653a..0422e7e95c5 100644 --- a/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java +++ b/src/main/java/org/apache/commons/lang3/concurrent/BasicThreadFactory.java @@ -20,6 +20,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.Validate; /** @@ -224,17 +225,11 @@ private void initializeThread(final Thread thread) { thread.setName(String.format(getNamingPattern(), count)); } - if (getUncaughtExceptionHandler() != null) { - thread.setUncaughtExceptionHandler(getUncaughtExceptionHandler()); - } + ObjectUtils.acceptIfNonNull(getUncaughtExceptionHandler(), thread::setUncaughtExceptionHandler); - if (getPriority() != null) { - thread.setPriority(getPriority().intValue()); - } + ObjectUtils.acceptIfNonNull(getPriority(), p -> thread.setPriority(p.intValue())); - if (getDaemonFlag() != null) { - thread.setDaemon(getDaemonFlag().booleanValue()); - } + ObjectUtils.acceptIfNonNull(getDaemonFlag(), d -> thread.setDaemon(d.booleanValue())); } /**