This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git
The following commit(s) were added to refs/heads/master by this push:
new 5b7ca64b1 Fix collate keeping duplicate nulls when includeDuplicates
is false (#715)
5b7ca64b1 is described below
commit 5b7ca64b122fade798413a14bfb5276a770aaec1
Author: Naveed Khan <[email protected]>
AuthorDate: Sat Jul 18 13:56:05 2026 +0000
Fix collate keeping duplicate nulls when includeDuplicates is false (#715)
---
src/changes/changes.xml | 1 +
.../java/org/apache/commons/collections4/CollectionUtils.java | 4 +++-
.../org/apache/commons/collections4/CollectionUtilsTest.java | 11 +++++++++++
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5b7045aaf..ec165e974 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,7 @@
<body>
<release version="4.6.0" date="YYYY-MM-DD" description="This is a feature
and maintenance release. Java 8 or later is required.">
<!-- FIX -->
+ <action type="fix" dev="ggregory" due-to="Naveed Khan, Gary
Gregory">CollectionUtils.collate(Iterable, Iterable, Comparator, boolean) does
not remove duplicate null elements when includeDuplicates is false.</action>
<action type="fix" dev="ggregory" due-to="Naveed Khan, Gary
Gregory">DualHashBidiMap, DualLinkedHashBidiMap, and DualTreeBidiMap entrySet()
Map.Entry.setValue(Object) returns the new value instead of the previous
value.</action>
<action type="fix" dev="ggregory" due-to="Naveed Khan, Gary
Gregory">AbstractMapBag and AbstractMapMultiSet.add(Object, int) overflow the
size and element count past Integer.MAX_VALUE.</action>
<action type="fix" dev="ggregory" due-to="Naveed
Khan">CompositeCollection, CompositeSet, CompositeMap, AbstractMultiValuedMap
and AbstractMultiSet size() overflow int when the total exceeds
Integer.MAX_VALUE.</action>
diff --git a/src/main/java/org/apache/commons/collections4/CollectionUtils.java
b/src/main/java/org/apache/commons/collections4/CollectionUtils.java
index 1d7209446..966d323fd 100644
--- a/src/main/java/org/apache/commons/collections4/CollectionUtils.java
+++ b/src/main/java/org/apache/commons/collections4/CollectionUtils.java
@@ -481,12 +481,14 @@ public class CollectionUtils {
}
final ArrayList<O> mergedList = new ArrayList<>(totalSize);
O lastItem = null;
+ boolean first = true;
while (iterator.hasNext()) {
final O item = iterator.next();
- if (lastItem == null || !lastItem.equals(item)) {
+ if (first || !Objects.equals(lastItem, item)) {
mergedList.add(item);
}
lastItem = item;
+ first = false;
}
mergedList.trimToSize();
return mergedList;
diff --git
a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
index 4607cc2b6..99ddfa302 100644
--- a/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/CollectionUtilsTest.java
@@ -647,6 +647,17 @@ class CollectionUtilsTest extends MockTestCase {
assertEquals(combinedList, result2, "Merge two lists 2 - ignore
duplicates");
}
+ @Test
+ void testCollateIgnoreDuplicatesWithNullElements() {
+ final Comparator<String> nullsFirst =
Comparator.nullsFirst(Comparator.<String>naturalOrder());
+ final List<String> left = Arrays.asList(null, "a");
+ final List<String> right = Arrays.asList(null, "a");
+ // a null element is a legal, sorted value here, so consecutive nulls
must
+ // collapse just like any other duplicate when includeDuplicates is
false
+ assertEquals(Arrays.asList(null, "a"), CollectionUtils.collate(left,
right, nullsFirst, false));
+ assertEquals(Arrays.asList(null, null, "a", "a"),
CollectionUtils.collate(left, right, nullsFirst, true));
+ }
+
@Test
void testCollect() {
final Transformer<Number, Long> transformer =
TransformerUtils.constantTransformer(2L);