You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/08/14 22:12:00 UTC
[commons-collections] branch master updated: [COLLECTIONS-726] Add
lambdas function to provide default values in MapUtils. Implementation
based on the idea of PR #81. Closes #81.
This is an automated email from the ASF dual-hosted git repository.
ggregory 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 b1511c7 [COLLECTIONS-726] Add lambdas function to provide default values in MapUtils. Implementation based on the idea of PR #81. Closes #81.
b1511c7 is described below
commit b1511c79aa749a245b48f5bf18c22e9c203882f0
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Aug 14 15:11:56 2019 -0700
[COLLECTIONS-726] Add lambdas function to provide default values in
MapUtils. Implementation based on the idea of PR #81. Closes #81.
- The implementation is much more concise than the PR.
- Sort methods.
- Line length 120.
- Close HTML tags in Javadoc.
---
src/changes/changes.xml | 1961 +++++++--------
.../org/apache/commons/collections4/MapUtils.java | 2640 +++++++++++---------
.../apache/commons/collections4/MapUtilsTest.java | 126 +-
3 files changed, 2518 insertions(+), 2209 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 69aa007..907bec1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -1,979 +1,982 @@
-<?xml version="1.0"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<document>
- <properties>
- <title>Apache Commons Collections Release Notes</title>
- </properties>
- <body>
- <release version="4.5" date="2019-MM-DD" description="Maintenance release.">
- <action issue="COLLECTIONS-724" dev="ggregory" type="updated." due-to="Eitan Adler">
- Simplify two remove-if loops #77.
- </action>
- </release>
- <release version="4.4" date="2019-07-05" description="Maintenance release.">
- <action issue="COLLECTIONS-710" dev="ggregory" type="fix" due-to="Yu Shi, Gary Gregory">
- NullPointerExceptions in CompositeCollection, CompositeSet, and CompositeMap.
- </action>
- <action issue="COLLECTIONS-715" dev="ggregory" type="add" due-to="morningmemo, Gary Gregory">
- Implement Collection's removeIf().
- </action>
- <action issue="COLLECTIONS-718" dev="ggregory" type="update" due-to="Eitan Adler">
- Fix LRUMap exception message.
- </action>
- <action issue="COLLECTIONS-719" dev="ggregory" type="add" due-to="Gary Gregory">
- Create a PropertiesFactory and SortedPropertiesFactory.
- </action>
- <action issue="COLLECTIONS-719" dev="ggregory" type="add" due-to="Stephan Windmüller, Bruno P. Kinoshita">
- Support Transformer for LazyList #52.
- </action>
- <action issue="COLLECTIONS-723" dev="ggregory" type="add" due-to="Eitan Adler, SOC, Bruno P. Kinoshita">
- Make use of FunctionalInterface #48.
- </action>
- <action issue="COLLECTIONS-716" dev="ggregory" type="update" due-to="Sebb">
- Don't include email address in Exception messages.
- </action>
- </release>
- <release version="4.3" date="2018-12-21" description="Update from Java 7 to Java 8, bug fixes, and small changes.">
- <action issue="COLLECTIONS-691" dev="kinow" type="fix" due-to="Eitan Adler">
- Use boolean operator for boolean result.
- </action>
- <action issue="COLLECTIONS-688" dev="ggregory" type="update">
- Update platform requirement from Java 7 to 8.
- </action>
- <action issue="COLLECTIONS-689" dev="ggregory" type="update" due-to="Richard Walker">
- Link to Javadoc API broken.
- </action>
- <action issue="COLLECTIONS-692" dev="ggregory" type="update" due-to="Gary Gregory, Eitan Adler">
- Replace use of deprecated Class#newInstance() PR #49.
- </action>
- <action issue="COLLECTIONS-696" dev="ggregory" type="add" due-to="Maxim Solodovnik">
- AbstractReferenceMap made easier for subclassing; PR #51.
- </action>
- <action issue="COLLECTIONS-701" dev="ggregory" type="fix" due-to="Shin Hong, Don Jeba">
- StackOverflowError in SetUniqueList.add() when it receives itself.
- </action>
- <action issue="COLLECTIONS-703" dev="ggregory" type="fix" due-to="Tomas Tulka">
- The PassiveExpiringMap#put() method should return the previous record only if not expired.
- </action>
- <action issue="COLLECTIONS-706" dev="ggregory" type="fix" due-to="Richard Eckart de Castilho, Gary Gregory">
- Add SetUtils.unmodifiableSet(T... items) method.
- </action>
- <action issue="COLLECTIONS-709" dev="ggregory" type="fix" due-to="Robert Wertman">
- MultiSet.Entry::getCount() isn't 0 after removing the last element.
- </action>
- </release>
- <release version="4.2" date="2018-07-11" description="Update from Java 6 to Java 7, bug fixes, and small changes.">
- <action issue="COLLECTIONS-681" dev="kinow" type="add" due-to="Stephan Fuhrmann">
- Add test for MultiSetUtils
- </action>
- <action issue="COLLECTIONS-599" dev="ggregory" type="fix" due-to="Tejas Patel, Saleem Akbar, Gary Gregory">
- HashEntry array object naming data initialized with double the size during deserialization.
- </action>
- <action issue="COLLECTIONS-662" dev="chtompki" type="fix" due-to="Vamsi Kavuri">
- Unit tests MapUtilsTest and ListIteratorWrapperTest no longer fail on Java 9.
- </action>
- <action issue="COLLECTIONS-661" dev="kinow" type="fix">
- Intermittent test failures in Windows for HashSetValuedHashMap.
- </action>
- <action issue="COLLECTIONS-660" dev="kinow" type="fix">
- Uncomment test in AbstractMapTest regarding LRUMap equals.
- </action>
- <action issue="COLLECTIONS-658" dev="britter" type="add">
- Add Automatic-Module-Name MANIFEST entry for Java 9 compatibility.
- </action>
- <action issue="COLLECTIONS-656" dev="ggregory" type="fix">
- Fix site build on Java 8.
- </action>
- <action issue="COLLECTIONS-653" dev="kinow" type="fix">
- Update Javadoc to Build on Java 1.8.
- </action>
- <action issue="COLLECTIONS-606" dev="chtompki" type="fix" due-to="Vamsi Kavuri">
- Build status, Coverage status and Maven central weren't in README.md
- </action>
- <action issue="COLLECTIONS-602" dev="kinow" type="update" due-to="John Mark">
- Improve efficiency of DefaultedMap.get.
- </action>
- <action issue="COLLECTIONS-603" dev="kinow" type="update" due-to="Artem Konovalov">
- Small improvements for generics, conditional statements, and warnings suppressions.
- </action>
- <action issue="COLLECTIONS-655" dev="ggregory" type="update">
- Update platform from Java 6 to Java 7.
- </action>
- <action issue="COLLECTIONS-594" dev="ggregory" type="fix" due-to="Javen O'Neal">
- Web site spelling error: MultiValuedMapeList.
- </action>
- <action issue="COLLECTIONS-597" dev="ggregory" type="fix" due-to="Enrique">
- Correction of Javadoc for org.apache.commons.collections4.functors.CatchAndRethrowClosure.
- </action>
- <action issue="COLLECTIONS-589" dev="ggregory" type="add" due-to="Gary Gregory">
- Add null-safe MapUtils.size(Map<?, ?>) method.
- </action>
- <action issue="COLLECTIONS-586" dev="ggregory" type="add" due-to="Shailender Bathula, Gary Gregory">
- PatriciaTrie prefixMap clear throws NullPointerException.
- </action>
- <action issue="COLLECTIONS-654" dev="ggregory" type="add">
- Add class SortedProperties to sort keys.
- </action>
- <action issue="COLLECTIONS-666" dev="ggregory" type="update" due-to="BELUGA BEHR">
- org.apache.commons.collections4.ListUtils.union(List, List) should pre-allocate result list.
- </action>
- <action issue="COLLECTIONS-669" dev="ggregory" type="update" due-to="BELUGA BEHR, Gary Gregory">
- Update org.apache.commons.collections4.CollectionUtils.addAll(Collection<C>, C[]) to addAll(Collection<C>, C...).
- </action>
- <action issue="COLLECTIONS-668" dev="ggregory" type="add" due-to="Gary Gregory">
- Add CollectionUtils containsAny method for primitive array: org.apache.commons.collections4.CollectionUtils.containsAny(Collection<?>, T...).
- </action>
- <action issue="COLLECTIONS-575" dev="ggregory" type="add" due-to="Guram Savinov, Grzegorz Rożniecki, Bruno P. Kinoshita, Gary Gregory">
- Synchronized queue wrapper in QueueUtils.
- </action>
- <action issue="COLLECTIONS-670" dev="ggregory" type="add" due-to="Gary Gregory">
- Add org.apache.commons.collections4.IteratorUtils.first(Iterator).
- </action>
- <action issue="COLLECTIONS-671" dev="ggregory" type="add" due-to="Gary Gregory">
- Add org.apache.commons.collections4.IterableUtils.first(Iterable).
- </action>
- <action issue="COLLECTIONS-678" dev="ggregory" type="fix" due-to="Oscar Luis Vera Pérez">
- The verification of unsupported iterator methods is not complete.
- </action>
- <action issue="COLLECTIONS-673" dev="ggregory" type="fix" due-to="John Mark, Stephan Fuhrmann">
- ListUtils.partition potential integer overflow.
- </action>
- </release>
- <release version="4.1" date="2015-11-28" description="This is a security and minor release.">
- <action issue="COLLECTIONS-508" dev="tn" type="add">
- Added new interfaces "MultiValuedMap", "ListValuedMap" and "SetValuedMap"
- as a replacement for "MultiMap". Decorators and implementations reside in
- the "multimap" package and a "MultiMapUtils" class has been added.
- The existing interface "MultiMap" as well as the concrete implementation
- "MultiValueMap" has been deprecated.
- </action>
- <action issue="COLLECTIONS-551" dev="tn" type="update">
- Deprecated various method in "CollectionUtils" in favor of similar
- methods in the newly introduced "IterableUtils".
- </action>
- <action issue="COLLECTIONS-580" dev="tn" type="update">
- Serialization support for unsafe classes in the functor package
- has been removed as this can be exploited for remote code execution
- attacks. Classes considered to be unsafe are: CloneTransformer,
- ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer,
- PrototypeCloneFactory, PrototypeSerializationFactory, WhileClosure.
- </action>
- <action issue="COLLECTIONS-580" dev="tn" type="fix">
- Added validation when de-serializing a "MultiValueMap#ReflectionFactory":
- only Collection classes are allowed, otherwise an UnsupportedOperationException
- will be thrown during de-serialization.
- </action>
- <action issue="COLLECTIONS-567" dev="tn" type="add">
- Added new MultiSet interface which is intended to be a replacement for
- the Bag interface. The main difference is that a MultiSet is fully compatible
- to the Collection contract.
- </action>
- <action issue="COLLECTIONS-576" dev="tn" type="fix" due-to="Stephan Roch">
- Subclasses of MultiKey did not re-calculate their hashcode after de-serialization.
- </action>
- <action issue="COLLECTIONS-572" dev="tn" type="add">
- Added set operations to "SetUtils": union, difference, intersection and disjunction.
- The operations return a view of the result that is backed by the input sets.
- </action>
- <action issue="COLLECTIONS-570" dev="tn" type="update">
- All constructors and static factory methods will now throw a "NullPointerException" if
- a required input argument is null. Previously sometimes a "IllegalArgumentException" was used.
- </action>
- <action issue="COLLECTIONS-571" dev="tn" type="update">
- Deprecated methods "synchronizedCollection(Collection)" and "unmodifiableCollection(Collection)"
- in class "CollectionUtils", the corresponding methods in "java.util.Collections" should be used instead.
- </action>
- <action issue="COLLECTIONS-566" dev="tn" type="fix">
- "IteratorUtils#collate(...)" methods did not use natural ordering when a
- null comparator was provided.
- </action>
- <action issue="COLLECTIONS-557" dev="tn" type="add" due-to="Philippe Mouawad">
- Added support to specify the initial size of a "LRUMap".
- </action>
- <action issue="COLLECTIONS-565" dev="tn" type="add">
- Added decorators for "NavigableSet" interface.
- </action>
- <action issue="COLLECTIONS-464,COLLECTIONS-442" dev="tn" type="add">
- Added new class "FluentIterable" to support a fluent API for manipulating
- Iterable instances. Additionally various supporting methods have been
- added to "IterableUtils" and "IteratorUtils".
- </action>
- <action issue="COLLECTIONS-464" dev="tn" type="add">
- Added new "ZippingIterator" and factory methods "IteratorUtils#zippingIterator(...)".
- </action>
- <action issue="COLLECTIONS-464" dev="tn" type="add">
- Added new decorator "SkippingIterator" and factory methods "IteratorUtils#skippingIterator(...)".
- </action>
- <action issue="COLLECTIONS-556" dev="tn" type="add">
- Added method "SetUtils#newIdentityHashSet()" which returns a new identity HashSet
- using reference-equality instead of object-equality.
- </action>
- <action issue="COLLECTIONS-562" dev="tn" type="update">
- Upgraded minimum java requirement to Java 6 (up from Java 5).
- </action>
- <action issue="COLLECTIONS-395" dev="tn" type="add" due-to="David Hawthorne">
- Added method "LRUMap#get(Object, boolean)" that allows to query the map
- without affecting the least recently used order.
- </action>
- <action issue="COLLECTIONS-558" dev="tn" type="fix" due-to="Felix Rabe">
- Changed return type of "ListOrderedSet#remove(int)" from Object to the generic type parameter.
- </action>
- <action issue="COLLECTIONS-555" dev="tn" type="fix" due-to="M Kim">
- Added clarification to javadoc of "TreeBag#add(Object)" wrt null arguments.
- </action>
- <action issue="COLLECTIONS-427" dev="tn" type="add" due-to="Gonçalo Marques">
- Added "toString(...)" methods to newly created "IterableUtils" and existing "IteratorUtils"
- to get a string representation of an Iterable/Iterator instance similar to "Arrays#toString(...)".
- </action>
- <action issue="COLLECTIONS-427" dev="tn" type="fix">
- Reverted performance improvement for "SetUniqueList#retainAll(Collection)"
- introduced in 4.0. Added clarifying javadoc wrt runtime complexity instead.
- </action>
- <action issue="COLLECTIONS-426" dev="tn" type="fix">
- Reverted performance improvement for "ListOrderedSet#retainAll(Collection)"
- introduced in 4.0. Added clarifying javadoc wrt runtime complexity instead.
- </action>
- <action issue="COLLECTIONS-530" dev="tn" type="fix" due-to="Erik">
- Added a Builder for "PredicatedCollection". Elements added to the builder
- that fail the predicate will not throw an IllegalArgumentException. The builder
- supports creating predicated lists, bags, sets and queues.
- </action>
- <action issue="COLLECTIONS-545" dev="tn" type="fix" due-to="Oswaldo Olivo">
- Documented runtime complexity of "CollectionUtils#removeAll(Collection, Collection).
- </action>
- <action issue="COLLECTIONS-543" dev="tn" type="fix">
- "AbstractCollectionDecorator" doesn't forward equals and hashCode anymore.
- </action>
- <action issue="COLLECTIONS-544" dev="tn" type="fix" due-to="Oswaldo Olivo">
- Documented runtime complexity of "CollectionUtils#retainAll(Collection, Collection).
- </action>
- <action issue="COLLECTIONS-542" dev="tn" type="fix">
- "AbstractHashedMap" still inherits from "AbstractMap", contrary to what
- the class javadoc stated. The inheritance will now be removed in v5.0.
- </action>
- <action issue="COLLECTIONS-539" dev="tn" type="add" due-to="Guram Savinov">
- Changed scope of "CircularFifoQueue#isAtFullCapacity()" to public.
- </action>
- <action issue="COLLECTIONS-525" dev="tn" type="fix" due-to="Zigler Zhang">
- The map returned by "PatriciaTrie#prefixMap()" did not contain all keys
- that are prefixed by the given search key in some rare cases.
- </action>
- <action issue="COLLECTIONS-511" dev="tn" type="add" due-to="Nathan Blomquist, Brent Worden">
- Added new methods "IterableUtils#partition(...)" to partition an input collection
- into separate output collections based on evaluation of one or more predicates.
- </action>
- <action issue="COLLECTIONS-537" dev="tn" type="fix" due-to="Frank Jakop">
- Harmonized signature of factory methods for functor-related classes which take
- a collection as input with their array counterparts.
- </action>
- <action issue="COLLECTIONS-540" dev="tn" type="fix" due-to="Daniel Stewart, Issam El Atif">
- Added overloaded method "CollectionUtils#get(Enumeration, int)" and simplified
- code for "CollectionUtils#get(Object, int)".
- </action>
- <action issue="COLLECTIONS-536" dev="tn" type="fix" due-to="Tagir Valeev">
- Improved check for null input in "MapUtils#putAll(Map, Object[])".
- </action>
- <action issue="COLLECTIONS-534" dev="tn" type="fix" due-to="Oswaldo Olivo">
- Added clarifying javadoc wrt runtime complexity of "CollectionBag#retainAll".
- </action>
- <action issue="COLLECTIONS-529" dev="tn" type="add" due-to="Alexander Muthmann, Dipanjan Laha">
- Added methods "removeAll(...)" and "retainAll(...)" to "CollectionUtils" that perform
- equality checks using the provided "Equator" object instead of "Object#equals()".
- </action>
- <action issue="COLLECTIONS-531" dev="tn" type="fix" due-to="Dipanjan Laha">
- Use correct type bounds in
- "CollectionUtils#isEqualCollection(Collection, Collection, Equator)" to
- prevent a "ClassCastException" at runtime for invalid inputs.
- </action>
- <action issue="COLLECTIONS-523" dev="tn" type="fix" due-to="Thiago Andrade">
- Removed unneeded private method in "PassiveExpiringMap".
- </action>
- <action issue="COLLECTIONS-516" dev="tn" type="fix" due-to="Cyrille Artho">
- Added clarification to the javadoc of "MapUtils#toProperties(Map)" in case
- of null keys/values.
- </action>
- <action issue="COLLECTIONS-524" dev="tn" type="fix" due-to="J Goodfellow">
- "ListOrderedSet#listOrderedSet(List)" did not remove duplicates from the
- input list as advertised in the javadoc.
- </action>
- <action issue="COLLECTIONS-521" dev="tn" type="fix" due-to="Maxime Nay">
- "MultiKeyMap" was throwing a "NullPointerException" for various operations
- if two key arguments have been used and the second was "null".
- </action>
- <action issue="COLLECTIONS-522" dev="tn" type="fix" due-to="Erik">
- Updated code example for "PredicatedList".
- </action>
- <action issue="COLLECTIONS-512" dev="tn" type="fix" due-to="Cyrille Artho">
- "TransformingComparator" and "FixedOrderComparator" did not comply with
- the contract of "Object#equals".
- </action>
- <action issue="COLLECTIONS-510" dev="tn" type="fix" due-to="Hollis Waite">
- Fix compilation errors when using source level 1.8 and a recent java 8 compiler.
- </action>
- <action issue="COLLECTIONS-509" dev="tn" type="fix">
- Clarified javadoc of "CollectionBag" wrt changes from the original Bag interface.
- </action>
- <action issue="COLLECTIONS-507" dev="tn" type="fix" due-to="Gerson">
- Removed wrong type bounds for "ComparatorUtils#chainedComparator(...)".
- </action>
- <action issue="COLLECTIONS-506" dev="tn" type="fix" due-to="Anthony Communier">
- Added javadoc clarification to class "CollectionUtils" that input objects which
- override "Object#equals(Object)" must also maintain the general contract of
- "Object#hashCode()" as various utility methods take advantage of sets/maps/bags.
- </action>
- <action issue="COLLECTIONS-503" dev="tn" type="add" due-to="Josh Cain">
- Added new transformer "IfTransformer" and factory methods "TransformerUtils#ifTransformer(...)"
- which replace "TransformerUtils#switchTransformer(Predicate, Transformer, Transformer)".
- </action>
- <action issue="COLLECTIONS-471" dev="tn" type="add" due-to="Radford Tam">
- Added new decorator "BoundedIterator" and factory methods "IteratorUtils#boundedIterator(...)".
- </action>
- </release>
- <release version="4.0" date="2013-11-27" description="
-This is a major release: It combines bug fixes, new features and
-changes to existing features.
-
-Most notable changes are: use of generics and other language features introduced in Java 5 (varargs, Iterable),
-removed deprecated classes / methods and features which are now supported by the JDK,
-replaced Buffer interface with java.util.Queue,
-added concept of split maps with respective interfaces Put / Get (see also package splitmap),
-added new Trie interface together with an implementation of a Patricia Trie.
-
-Because of the base package name change, this release can be used together
-with earlier versions of Commons Collections.
-The minimal version of the Java platform required to compile and use
-Commons Collections is Java 5.
-Users are encouraged to upgrade to this version as, in addition to new
-features, this release includes numerous bug fixes.
- ">
- <action issue="COLLECTIONS-502" dev="tn" type="update">
- Resolved generic parameter inconsistency for various static fields, e.g. BagUtils.EMPTY_BAG,
- TruePredicate.INSTANCE and many others. All accessible static fields use raw types so that
- they can be used directly without explicit casting. To avoid compiler warnings about unchecked
- conversion and/or rawtypes use the corresponding factory methods, e.g. BagUtils.emptyBag().
- </action>
- <action issue="COLLECTIONS-501" dev="tn" type="update">
- Renamed methods "V MultiKeyMap#remove(Object, Object, ...)" to
- "V MultiKeyMap#removeMultiKey(Object, Object, ...)" to avoid future conflicts
- with a default method of the Map interface in Java 8.
- </action>
- <action issue="COLLECTIONS-500" dev="tn" type="update">
- Renamed "V MultiMap#remove(K, V)" to "boolean MultiMap#removeMapping(K, V)"
- to avoid future conflicts with a default method of the Map interface in Java 8.
- </action>
- <action issue="COLLECTIONS-499" dev="tn" type="update">
- Refactored the test framework for Bag implementations to extend from
- "AbstractCollectionTest" by decorating the concrete Bag instance with
- a CollectionBag or CollectionSortedBag.
- </action>
- <action issue="COLLECTIONS-498" dev="tn" type="fix">
- "CollectionBag" will now also respect the contract of the decorated bag in case
- a null argument is provided to either removeAll or retainAll.
- </action>
- <action issue="COLLECTIONS-497" dev="tn" type="add">
- Added bag decorator "CollectionSortedBag" which decorates a SortedBag to make it
- comply with the Collection contract.
- </action>
- <action issue="COLLECTIONS-496" dev="tn" type="update">
- "UnmodifiableBoundedCollection" does now also implement the marker interface "Unmodifiable"
- similar as all other unmodifiable decorators.
- </action>
- <action issue="COLLECTIONS-495" dev="tn" type="fix">
- "UnmodifiableTrie#unmodifiableTrie(Trie)" will not decorate again an already
- unmodifiable Trie. Also the return type has been changed to "Trie" to be consistent
- with other Unmodifiable decorators.
- </action>
- <action issue="COLLECTIONS-494" dev="tn" type="update" due-to="Emmanuel Bourg">
- Moved "Equator" interface to base package for consistency.
- </action>
- <action issue="COLLECTIONS-488" dev="tn" type="add" due-to="Josh Cain">
- Added "CollectionsUtils#matchesAll(Iterable, Predicate)" to test if all elements
- of a collection match a given predicate.
- </action>
- <action issue="COLLECTIONS-485" dev="tn" type="fix" due-to="Hollis Waite">
- Accept wildcard input where possible, e.g. in copy-constructors, Unmodifiable* decorators
- and iterators.
- </action>
- <action issue="COLLECTIONS-481" dev="tn" type="fix" due-to="Hollis Waite">
- No collision detection/resolution was performed when calling "CompositeSet#addComposited(...)"
- with more than one Set as argument. Additionally use varargs parameters instead of arrays
- in CompositeSet and CompositeCollection constructor and addComposited method.
- </action>
- <action issue="COLLECTIONS-480" dev="tn" type="update" due-to="Hollis Waite">
- Narrow return type of "BidiMap#values()" to Set as the values are required to be unique.
- </action>
- <action issue="COLLECTIONS-475" dev="tn" type="fix">
- Fixed conversion of timeout parameters in "PassiveExpiringMap".
- </action>
- <action issue="COLLECTIONS-474" dev="sebb" type="fix" due-to="Ning Chen">
- Exception in "ListOrderedMap#putAll" if map contains null values.
- </action>
- <action issue="COLLECTIONS-473" dev="tn" type="update" due-to="sebb">
- Made field "collection" in class "AbstractCollectionDecorator" private and added
- setter "setCollection(Collection)" with scope protected to set the decorated collection
- during de-serialization.
- </action>
- <action issue="COLLECTIONS-472" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "AbstractMapBag#containsAll(Collection)" by returning immediately
- after a difference has been found.
- </action>
- <action issue="COLLECTIONS-470" dev="tn" type="update" due-to="sebb">
- Renamed class "TransformedMap" in package "splitmap" to "TransformedSplitMap" to avoid
- name clash with similar class in package "map".
- </action>
- <action issue="COLLECTIONS-468" dev="tn" type="add">
- Added bag decorator "CollectionBag" which decorates a bag to make it comply with the
- Collection contract.
- </action>
- <action issue="COLLECTIONS-466" dev="tn" type="update">
- Replaced "Collection" with "Iterable" for method arguments where applicable.
- </action>
- <action issue="COLLECTIONS-463" dev="tn" type="add" due-to="Andy Seaborne, Claude Warren">
- Added "PushbackIterator" decorator to support pushback of elements during iteration.
- </action>
- <action issue="COLLECTIONS-462" dev="tn" type="add" due-to="Andy Seaborne, Claude Warren">
- Added "PeekingIterator" decorator to support one-element lookahead during iteration.
- </action>
- <action issue="COLLECTIONS-461" dev="tn" type="fix" due-to="Matt Benson, sebb">
- Added additional clarification to javadoc of interface "Put" wrt return type of
- "put(Object, Object)" method.
- </action>
- <action issue="COLLECTIONS-460" dev="tn" type="update">
- Changed "IteratorChain" to use internally a "Queue" instead of a "List". Iterators are
- removed from the queue once used and can be garbage collected after being exhausted.
- Additionally removed the methods "setIterator(Iterator)" and "getIterators()".
- </action>
- <action issue="COLLECTIONS-459" dev="tn" type="update" due-to="sebb">
- Removed method "setArray(Object)" in class ArrayIterator and method "setArray(Object[])"
- in class ObjectArrayIterator and made fields array, startIndex and endIndex final.
- </action>
- <action issue="COLLECTIONS-458" dev="sebb" type="remove">
- Removed unused class "AbstractUntypedCollectionDecorator<E, D>".
- </action>
- <action issue="COLLECTIONS-456" dev="tn" type="add">
- Added methods "ListUtils#longestCommonSubsequence(...)" to get the longest common subsequence
- of arbitrary lists or CharSequences.
- </action>
- <action issue="COLLECTIONS-455" dev="sebb" type="update">
- Changed scope of fields to private where appropriate.
- </action>
- <action issue="COLLECTIONS-454" dev="tn" type="update">
- An iterator over a "Flat3Map#entrySet()" will now return
- independent Map.Entry objects that will not change anymore when
- the iterator progresses.
- </action>
- <action issue="COLLECTIONS-453" dev="tn" type="update">
- Several closure and transformer implementations in the functors package
- will now copy an array as input to their constructor (e.g. ChainedClosure).
- </action>
- <action issue="COLLECTIONS-452" dev="tn" type="update">
- Change base package to org.apache.commons.collections4.
- </action>
- <action issue="COLLECTIONS-451" dev="tn" type="update">
- The constructors for all Utils classes are now private to prevent instantiation.
- </action>
- <action issue="COLLECTIONS-450" dev="tn" type="add" due-to="J. Moldawski">
- Added methods "forAllButLastDo(Collection, Closure)" and "forAllButLastDo(Iterator, Closure)"
- to class "CollectionUtils".
- </action>
- <action issue="COLLECTIONS-447" dev="tn" type="fix" due-to="Jeffrey Barnes">
- Tree traversal with a TreeListIterator will not be affected anymore by
- the removal of an element directly after a call to previous().
- </action>
- <action issue="COLLECTIONS-446" dev="tn" type="add" due-to="Matt Lachman">
- Added method "CollectionUtils#isEqualCollection(Collection, Collection, Equator)".
- </action>
- <action issue="COLLECTIONS-445" dev="tn" type="fix">
- Adapt and/or ignore several unit tests when run on a IBM J9 VM (specification version 1.6.0)
- due to a faulty "java.util.TreeMap" implementation.
- </action>
- <action issue="COLLECTIONS-444" dev="tn" type="fix" due-to="Thomas Vahrst, John Vasileff">
- SetUniqueList.set(int, E) now works correctly if the object to be inserted
- is already placed at the given position.
- </action>
- <action issue="COLLECTIONS-441" dev="tn" type="fix" due-to="Thomas Vahrst">
- MultiKeyMap.clone() now correctly calls super.clone().
- </action>
- <action issue="COLLECTIONS-436" dev="tn" type="add" due-to="Arman Sharif">
- Added "emptyIfNull" methods to classes "CollectionUtils", "ListUtils", "SetUtils"
- and "MapUtils".
- </action>
- <action issue="COLLECTIONS-433" dev="tn" type="fix" due-to="Jeffrey Barnes">
- Improve performance of "TreeList#addAll" and "TreeList(Collection)" by converting
- the input collection into an AVL tree and efficiently merge it into the existing tree.
- </action>
- <action issue="COLLECTIONS-432" dev="tn" type="update">
- Replaced "Buffer" interface with "java.util.Queue". Kept "CircularFifoQueue"
- as well as "Predicated", "Transformed" and "Unmodifiable" decorators.
- </action>
- <action issue="COLLECTIONS-429,COLLECTIONS-434" dev="tn" type="add" due-to="Adrian Nistor, Mert Guldur">
- Added method "CollectionUtils#containsAll(Collection, Collection)" with guaranteed
- runtime complexity of O(n + m) and space complexity of O(n). This method may yield much
- better performance than "Collection#containsAll(Collection)" depending on the use-case and
- type of collection used.
- </action>
- <action issue="COLLECTIONS-427" dev="brentworden" type="fix" due-to="Mert Guldur">
- Fixed performance issue in "SetUniqueList#retainAll" method for large collections.
- </action>
- <action issue="COLLECTIONS-426" dev="brentworden" type="fix" due-to="Adrian Nistor">
- Fixed performance issue in "ListOrderedSet#retainAll" method for large collections.
- </action>
- <action issue="COLLECTIONS-425" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "ListOrderedMap#remove(Object)" method.
- </action>
- <action issue="COLLECTIONS-424" dev="tn" type="update" due-to="Michael Pradel">
- "CompositeSet" does not inherit from "CompositeCollection" anymore. The inner class
- "SetMutator" has been updated accordingly.
- </action>
- <action issue="COLLECTIONS-422" dev="tn" type="add" due-to="Benoit Corne">
- Added method "CollectionUtils#permutations(Collection)" and class "PermutationIterator"
- to generate unordered permutations of a collection.
- </action>
- <action issue="COLLECTIONS-421" dev="tn" type="fix" due-to="Benedikt Ritter">
- Update javadoc for "ListUtils#lazyList()" and "ListUtils#fixedSizeList()".
- </action>
- <action issue="COLLECTIONS-419" dev="tn" type="fix" due-to="Adrian Nistor">
- Added clarifying javadoc wrt runtime complexity of "AbstractDualBidiMap#retainAll".
- </action>
- <action issue="COLLECTIONS-417" dev="tn" type="fix" due-to="Adrian Nistor">
- Added clarifying javadoc wrt runtime complexity of "AbstractLinkedList#retainAll".
- </action>
- <action issue="COLLECTIONS-415" dev="tn" type="fix" due-to="Adrian Nistor">
- Added clarifying javadoc wrt runtime complexity of "AbstractLinkedList#removeAll".
- </action>
- <action issue="COLLECTIONS-414" dev="tn" type="fix">
- Fixed several compilation issues with older Java 1.6 compilers.
- </action>
- <action issue="COLLECTIONS-413" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "removeAll()" method for sets returned by "DualHashBidiMap#entrySet()".
- </action>
- <action issue="COLLECTIONS-412" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "CollectionUtils#subtract" methods.
- </action>
- <action issue="COLLECTIONS-411" dev="tn" type="fix" due-to="Adrian Nistor">
- Fixed possible "IndexOutOfBoundsException" in "ListOrderedMap#putAll".
- </action>
- <action issue="COLLECTIONS-410" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "SetUniqueList#addAll" method.
- </action>
- <action issue="COLLECTIONS-409" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "ListOrderedSet#addAll" method.
- </action>
- <action issue="COLLECTIONS-408" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "SetUniqueList#removeAll".
- </action>
- <action issue="COLLECTIONS-407" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "ListOrderedSet#remove(Object)" in case the object is
- not contained in the Set.
- </action>
- <action issue="COLLECTIONS-406" dev="tn" type="fix" due-to="Adrian Nistor">
- Improved performance of "ListUtils#subtract" method.
- </action>
- <action issue="COLLECTIONS-405" dev="brentworden" type="add" due-to="Adam Dyga">
- Added "ListUtils#select" and "ListUtils#selectRejected" methods.
- </action>
- <action issue="COLLECTIONS-404" dev="luc" type="add" due-to="Jordane Sarda">
- Added an implementation of Eugene Myers difference algorithm in package
- o.a.c.c.sequence.
- </action>
- <action issue="COLLECTIONS-400" dev="tn" type="fix" due-to="Shin Hwei Tan">
- Added missing null check in "CollectionUtils#addIgnoreNull(Collection, Object)".
- </action>
- <action issue="COLLECTIONS-399" dev="tn" type="add" due-to="Sebb">
- Added new method "get(int)" to "CircularFifoQueue".
- </action>
- <action issue="COLLECTIONS-396" dev="tn" type="add" due-to="Jeff Rodriguez">
- Added "LazyIteratorChain" iterator.
- </action>
- <action issue="COLLECTIONS-393" dev="tn" type="add" due-to="Chris Shayan">
- Added "ListUtils#partition" method to split a List into consecutive sublists.
- </action>
- <action issue="COLLECTIONS-391" dev="tn" type="fix" due-to="Shin Hwei Tan">
- Fixed javadoc for "MapUtils#toProperties(Map)".
- </action>
- <action issue="COLLECTIONS-389" dev="tn" type="fix" due-to="Shin Hwei Tan">
- Clarified javadoc for "TransformerUtils#mapTransformer" for null input.
- </action>
- <action issue="COLLECTIONS-388" dev="tn" type="fix" due-to="Shin Hwei Tan">
- Clarified javadoc for "FactoryUtils#prototypeFactory" for null input.
- </action>
- <action issue="COLLECTIONS-384" dev="ggregory" type="fix" due-to="Shin Hwei Tan">
- Fixed inconsistent javadoc for "MapUtils#synchronizedMap(Map)".
- </action>
- <action issue="COLLECTIONS-383" dev="tn" type="add" due-to="Adrian Cumiskey">
- Added "CollectionUtils#forAllDo" implementation which takes an "Iterator" as input.
- </action>
- <action issue="COLLECTIONS-382" dev="tn" type="update" due-to="Olivier Lamy">
- Change maven coordinates to "org.apache.commons.commons-collections4".
- </action>
- <action issue="COLLECTIONS-381" dev="sebb" type="update" due-to="Olivier Lamy">
- Move the project structure to a standard maven layout.
- </action>
- <action issue="COLLECTIONS-380" dev="tn" type="fix" due-to="Dave Brosius">
- Fixed infinite loop when calling "UnmodifiableBoundedCollection#unmodifiableBoundedCollection()".
- </action>
- <action issue="COLLECTIONS-379" dev="tn" type="fix" due-to="Shin Hwei Tan">
- Fixed javadoc for several methods wrt expected NullPointerExceptions.
- </action>
- <action issue="COLLECTIONS-375" dev="tn" type="add" due-to="Ivan Hristov">
- Added method "ListUtils#defaultIfNull(List, List)".
- </action>
- <action issue="COLLECTIONS-372" dev="tn" type="update">
- TransformingComparator now supports different types for its input/output values.
- </action>
- <action issue="COLLECTIONS-364" dev="sebb" type="fix">
- "DualTreeBidiMap" now uses the correct comparator for the reverse map during de-serialization.
- </action>
- <action issue="COLLECTIONS-363" dev="sebb" type="fix">
- "TransformedMap" in the package "splitmap" can now be serialized.
- </action>
- <action issue="COLLECTIONS-362" dev="brentworden" type="update" due-to="Jean-Noel Rouvignac">
- "CollectionUtils#filter(Iterable, Predicate)" will now return whether the collection
- has been modified.
- </action>
- <action issue="COLLECTIONS-361" dev="tn" type="add" due-to="Jean-Noel Rouvignac">
- Add method "CollectionUtils#filterInverse(Iterable, Predicate)".
- </action>
- <action issue="COLLECTIONS-360" dev="jochen" type="fix" due-to="Sai Zhang">
- "FilterListIterator#hasNext" does not throw a NullPointerException anymore
- to comply to the Java iterator specification.
- </action>
- <action issue="COLLECTIONS-359" dev="bayard" type="fix" due-to="Mark Shead">
- "ListUtils#intersection(List, List)" will now also work correctly if there
- are duplicate elements in the provided lists.
- </action>
- <action issue="COLLECTIONS-352" dev="bayard" type="fix" due-to="Adam Gent">
- "AbstractCollectionDecorator" will now use internally "decorated()" to access
- the decorated collection.
- </action>
- <action issue="COLLECTIONS-351" dev="bayard" type="remove" due-to="Henri Yandell">
- Removed features which are now supported by the JDK.
- </action>
- <action issue="COLLECTIONS-350" dev="bayard" type="fix" due-to="Michael Akerman">
- Removed debug output in "MapUtils#getNumber(Map)".
- </action>
- <action issue="COLLECTIONS-348" dev="brentworden" type="fix" due-to="Paul Benedict">
- Fixed javadoc for all "transformedXXX(XXX)" methods in the respective Utils classes
- to clarify that existing objects in the list are not transformed.
- </action>
- <action issue="COLLECTIONS-343" dev="mbenson" type="fix" due-to="Goran Hacek">
- Singleton classes in package "functors" are now correctly de-serialized.
- </action>
- <action issue="COLLECTIONS-341" dev="mbenson" type="update" due-to="Goran Hacek">
- "NOPClosure" is now a final class.
- </action>
- <action issue="COLLECTIONS-340" dev="mbenson" type="fix" due-to="Goran Hacek">
- Removed broken methods "equals(Object)" and "hashCode()" in class "NOPClosure".
- </action>
- <action issue="COLLECTIONS-336" dev="bayard" type="fix" due-to="sebb">
- Simplified exceptions as the cause is available from the parent.
- </action>
- <action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
- Fixed cache assignment for "TreeBidiMap#entrySet".
- </action>
- <action issue="COLLECTIONS-334" dev="jochen" type="fix" due-to="sebb">
- Synchronized access to lock in "StaticBucketMap#size()".
- </action>
- <action issue="COLLECTIONS-332" dev="jochen" type="fix" due-to="Tom Parker">
- Added clarification to javadoc of "ListOrderedMap" that "IdentityMap" and
- "CaseInsensitiveMap" are not supported.
- </action>
- <action issue="COLLECTIONS-331" dev="jochen" type="fix" due-to="Michael Krkoska">
- Improve javadoc of "CollatingIterator" wrt the used "Comparator" and throw a
- NullPointerException in "CollatingIterator#least" if no comparator is set.
- </action>
- <action issue="COLLECTIONS-330" dev="mbenson" type="fix" due-to="Joerg Schaible">
- "LRUMap#keySet()#remove(Object)" will not throw a "ConcurrentModificationException" anymore.
- </action>
- <action issue="COLLECTIONS-328" dev="bayard" type="fix" due-to="Thomas Rogan, Jilles van Gurp">
- Improved performance of "ListUtils#intersection(List, List)".
- </action>
- <action issue="COLLECTIONS-327" dev="brentworden" type="add" due-to="sebb">
- Added serialVersionUID fields for "CompositeCollection", "CompositeSet",
- "EmptyMapMutator", "EmptySetMutator".
- </action>
- <action issue="COLLECTIONS-324" dev="tn" type="update" due-to="sebb">
- Fields transformer and decorated in class "TransformingComparator" are now final.
- </action>
- <action issue="COLLECTIONS-323" dev="jochen" type="fix" due-to="Maarten Brak">
- Changed behavior of "CaseInsensitiveMap" constructor to be compliant with "HashMap"
- in case the initial capacity is set to zero.
- </action>
- <action issue="COLLECTIONS-322" dev="tn" type="add" due-to="Thomas Vahrst">
- Added NodeListIterator and convenience methods in IteratorUtils to iterate over
- a org.w3c.dom.NodeList.
- </action>
- <action issue="COLLECTIONS-320" dev="bayard" type="fix" due-to="sebb">
- Improved performance of "StaticBucketMap#putAll(Map)" by iterating over the entry set.
- </action>
- <action issue="COLLECTIONS-319" dev="bayard" type="fix" due-to="sebb">
- Avoid redundant null check in "IteratorUtils#getIterator(Object)".
- </action>
- <action issue="COLLECTIONS-317" dev="bayard" type="fix" due-to="sebb">
- Use a private method to populate the object in "AbstractHashedMap(Map)".
- </action>
- <action issue="COLLECTIONS-316" dev="bayard" type="fix" due-to="ori">
- Fixed javadoc of "LRUMap" wrt to the maxSize parameter of the constructor.
- </action>
- <action issue="COLLECTIONS-313" dev="brentworden" type="add" due-to="David J. M. Karlsen">
- Added new abstract class "CatchAndRethrowClosure" that re-throws any checked exception
- as unchecked "FunctorException".
- </action>
- <action issue="COLLECTIONS-312" dev="tn" type="fix" due-to="Peter Lawrey, Gary Gregory">
- Use of final keyword where applicable, minor performance improvements by properly
- initializing the capacity of newly created collections when known in advance.
- </action>
- <action issue="COLLECTIONS-307" dev="tn" type="update" due-to="Christian Semrau, Thomas Vahrst">
- "SetUniqueList#subList()" will now return an unmodifiable list as changes to it
- may invalidate the parent list.
- </action>
- <action issue="COLLECTIONS-307" dev="bayard" type="fix" due-to="Christian Semrau">
- "SetUniqueList#subList()#contains(Object)" will now correctly check the subList
- rather than the parent list.
- </action>
- <action issue="COLLECTIONS-306" dev="brentworden" type="add" due-to="Chris Shayan">
- Added method "CollectionUtils#subtract(Iterable, Iterable, Predicate)".
- </action>
- <action issue="COLLECTIONS-304" dev="bayard" type="fix" due-to="Rafał Figas,Bjorn Townsend">
- "SetUniqueList#set(int, Object)" will now correctly enforce the uniqueness constraint.
- </action>
- <action issue="COLLECTIONS-303" dev="bayard" type="fix" due-to="Emmanuel Bourg">
- Improved javadoc for "Unmodifiable*" classes wrt behavior when the users tries
- to modify the collection.
- </action>
- <action issue="COLLECTIONS-298" dev="bayard" type="update" due-to="Benjamin Bentmann">
- Calling "CollectionUtils#sizeIsEmpty(null)" will now return true.
- </action>
- <action issue="COLLECTIONS-296" dev="tn" type="add" due-to="Julius Davies">
- Added methods "CollectionUtils#collate(...)" to merge two sorted Collections
- into a sorted List using the standard O(n) merge algorithm.
- </action>
- <action issue="COLLECTIONS-294" dev="bayard" type="fix" due-to="Benjamin Bentmann">
- "CaseInsensitiveMap" will now convert input strings to lower-case in a
- locale-independant manner.
- </action>
- <action issue="COLLECTIONS-293" dev="tn" type="add" due-to="Stephen Kestle">
- Added support for using custom "Equator" objects in "EqualPredicate".
- </action>
- <action issue="COLLECTIONS-289" dev="bayard" type="add" due-to="Fredrik Kjellberg">
- Added method "CollatingIterator#getIteratorIndex()".
- </action>
- <action issue="COLLECTIONS-256,COLLECTIONS-288" dev="bayard" type="fix" due-to="Paul Benedict">
- Fixed javadoc for "ListUtils#transformedList(List)" to clarify that existing objects
- in the list are not transformed.
- </action>
- <action issue="COLLECTIONS-286" dev="mbenson" type="add" due-to="Geoffrey De Smet">
- Added method "CollectionUtils#extractSingleton(Collection)".
- </action>
- <action issue="COLLECTIONS-285" dev="tn" type="add" due-to="Christian Gruenberg">
- Added serialization support for "TreeBidiMap".
- </action>
- <action issue="COLLECTIONS-280" dev="bayard" type="update" due-to="Chris Lewis">
- The predicate that rejected an object to be added to a "PredicatedCollection"
- is now contained in the respective exception message.
- </action>
- <action issue="COLLECTIONS-275" dev="tn" type="add" due-to="Stephen Kestle">
- Added "IndexedCollection" collection decorator which provides a map-like
- view on an existing collection.
- </action>
- <action issue="COLLECTIONS-272" dev="tn" type="add" due-to="Chaitanya Mutyala">
- Added serialization support for "FixedOrderComparator" and "TransformingComparator".
- </action>
- <action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
- "MultiKey" will now be correctly serialized/de-serialized.
- </action>
- <action issue="COLLECTIONS-265" dev="bayard" type="update" due-to="David Saff">
- "TreeBag" will now only accept "Comparable" objects as input when used with natural ordering.
- </action>
- <action issue="COLLECTIONS-263" dev="tn" type="add" due-to="John Hunsley">
- Added methods "MapUtils#populateMap(MultiMap, ...)" to support also "MultiMap" instances
- as input.
- </action>
- <action issue="COLLECTIONS-262" dev="bayard" type="fix" due-to="Lisen Mu">
- Fixed javadoc for methods "firstKey()" and "lastKey()" in class "AbstractLinkedMap".
- </action>
- <action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
- "Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
- if the size of the map is less or equal 3.
- </action>
- <action issue="COLLECTIONS-260" dev="mbenson" type="add" due-to="Stephen Kestle">
- Added constructor "TransformingComparator(Transformer)".
- </action>
- <action issue="COLLECTIONS-258" dev="tn" type="add" due-to="Nathan Blomquist">
- Added "DualLinkedHashBidiMap" bidi map implementation.
- </action>
- <action issue="COLLECTIONS-255" dev="mbenson" type="fix" due-to="Henri Yandell">
- Removed unused variables in "TreeBidiMap".
- </action>
- <action issue="COLLECTIONS-251,COLLECTIONS-321" dev="mbenson" type="update" due-to="Stephen Kestle">
- The static factory methods have been renamed from "getInstance()" to a camel-case
- version of the class name, e.g. "truePredicate()" for class "TruePredicate".
- </action>
- <action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
- "SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
- provided index.
- </action>
- <action issue="COLLECTIONS-242" dev="skestle" type="add">
- Added "Equator" interface.
- </action>
- <action issue="COLLECTIONS-241" dev="brentworden" type="add" due-to="Elifarley Callado Coelho">
- Added "PassiveExpiringMap" map decorator.
- </action>
- <action issue="COLLECTIONS-240" dev="bayard" type="update" due-to="Wouter de Vaal">
- "MultiValueMap" is now serializable.
- </action>
- <action issue="COLLECTIONS-237" dev="tn" type="add" due-to="Nils Kaiser, Alan Mehlo">
- Added method "MultiValueMap#iterator()" to return a flattened version of
- "entrySet().iterator()". Clarified javadoc for "entrySet()" that the returned Entry
- objects are unflattened, i.e. the Entry object for a given key contains all values
- mapped to this key.
- </action>
- <action issue="COLLECTIONS-235" dev="bayard" type="add" due-to="Nathan Egge">
- Added method "ListUtils#indexOf(List, Predicate)".
- </action>
- <action issue="COLLECTIONS-232" dev="bayard" type="fix" due-to="Mark Hindess">
- Fixed several unit tests which were using parameters to "assertEquals(...)" in wrong order.
- </action>
- <action issue="COLLECTIONS-231" dev="tn" type="update" due-to="Torsten Curdt">
- Return concrete class in static factory methods instead of base class interface
- (except for Unmodifiable decorators).
- </action>
- <action issue="COLLECTIONS-230,COLLECTIONS-297,COLLECTIONS-318" dev="bayard" type="update" due-to="Stepan Koltsov,sebb">
- "CollectionUtils#size(Collection)" now returns 0 when called with null as input.
- </action>
- <action issue="COLLECTIONS-229" dev="scolebourne" type="remove">
- Removed deprecated classes and methods.
- </action>
- <action issue="COLLECTIONS-228" dev="scolebourne" type="fix">
- "MultiValueMap#put(Object, Object)" and "MultiValueMap#putAll(Object, Collection)"
- now correctly return if the map has changed by this operation.
- </action>
- <action issue="COLLECTIONS-226" dev="bayard" type="add" due-to="Vasily Ivanov">
- Added method "ListOrderedMap#putAll(int, Map)".
- </action>
- <action issue="COLLECTIONS-225" dev="tn" type="add" due-to="Sam Berlin, Roger Kapsi">
- Added new "Trie" interface with a first concrete implementation "PatriciaTrie"
- together with decorators "Unmodifiable" and "Synchronized".
- </action>
- <action issue="COLLECTIONS-223" dev="bayard" type="update" due-to="Vasily Ivanov">
- "CollectionUtils#addAll(...)" methods now return if the collection has been changed
- by this operation.
- </action>
- <action issue="COLLECTIONS-221" dev="bayard" type="update" due-to="Pal Denes">
- "CompositeCollection", "CompositeMap" and "CompositeSet" are now serializable.
- </action>
- <action issue="COLLECTIONS-219" dev="scolebourne" type="fix" due-to="Tom Leccese">
- "CollectionUtils#removeAll" wrongly called "ListUtils#retainAll".
- </action>
- <action issue="COLLECTIONS-218" dev="skestle" type="update">
- The "CollectionUtils#select(Collection, Predicate, Collection)" method will now
- return the output collection.
- </action>
- <action issue="COLLECTIONS-217" dev="scolebourne" type="fix" due-to="Matt Bishop">
- Calling "setValue(Object)" on any Entry returned by a "Flat3Map" will now
- correctly set the value for the current entry.
- </action>
- <action issue="COLLECTIONS-216" dev="scolebourne" type="fix" due-to="Hendrik Maryns">
- "MultiKey#toString()" will now use "Arrays#toString(List)".
- </action>
- <action issue="COLLECTIONS-213" dev="brentworden" type="add" due-to="Dusan Chromy">
- Added support for resettable iterators in "IteratorIterable".
- </action>
- <action issue="COLLECTIONS-194" dev="bayard" type="add" due-to="Dave Meikle">
- Added methods "MapUtils#populateMap(Map, Iterable, Transformer, ...)".
- </action>
- <action issue="COLLECTIONS-182" dev="mbenson" type="update" due-to="Jim Cakalic">
- "CollectionUtils#forAllDo(Collection, Closure)" now returns the provided closure.
- </action>
- <action issue="COLLECTIONS-110,COLLECTIONS-243,COLLECTIONS-245,COLLECTIONS-247,
- COLLECTIONS-253,COLLECTIONS-273,COLLECTIONS-282" dev="multiple" type="update">
- Make generic versions of all classes in collections.
- </action>
- <action issue="COLLECTIONS-8" dev="brentworden" type="add" due-to="Rune Peter Bjørnstad">
- Added class "ComparatorPredicate".
- </action>
- </release>
- <release version="3.2.2" date="2015-11-15" description="This is a security and bugfix release.">
- <action issue="COLLECTIONS-580" dev="tn" type="update">
- Serialization support for unsafe classes in the functor package is disabled
- by default as this can be exploited for remote code execution attacks.
- To re-enable the feature the system property "org.apache.commons.collections.enableUnsafeSerialization"
- needs to be set to "true".
- Classes considered to be unsafe are: CloneTransformer, ForClosure, InstantiateFactory,
- InstantiateTransformer, InvokerTransformer, PrototypeCloneFactory,
- PrototypeSerializationFactory, WhileClosure.
- </action>
- <action issue="COLLECTIONS-538" dev="tn" type="fix" due-to="Trejkaz">
- "ExtendedProperties" will now use a privileged action to access the
- "file.separator" system property. In case the class does not have
- permission to read system properties, the "File#separator" field will
- be used instead.
- </action>
- <action issue="COLLECTIONS-447" dev="tn" type="fix" due-to="Jeffrey Barnes">
- Tree traversal with a TreeListIterator will not be affected anymore by
- the removal of an element directly after a call to previous().
- </action>
- <action issue="COLLECTIONS-444" dev="tn" type="fix" due-to="Thomas Vahrst, John Vasileff">
- SetUniqueList.set(int, Object) now works correctly if the object to be inserted
- is already placed at the given position.
- </action>
- <action issue="COLLECTIONS-350" dev="bayard" type="fix" due-to="Michael Akerman">
- Removed debug output in "MapUtils#getNumber(Map)".
- </action>
- <action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
- Fixed cache assignment for "TreeBidiMap#entrySet".
- </action>
- <action issue="COLLECTIONS-334" dev="jochen" type="fix" due-to="sebb">
- Synchronized access to lock in "StaticBucketMap#size()".
- </action>
- <action issue="COLLECTIONS-307" dev="bayard" type="fix" due-to="Christian Semrau">
- "SetUniqueList#subList()#contains(Object)" will now correctly check the subList
- rather than the parent list.
- </action>
- <action issue="COLLECTIONS-304" dev="bayard" type="fix" due-to="Rafał Figas,Bjorn Townsend">
- "SetUniqueList#set(int, Object)" will now correctly enforce the uniqueness constraint.
- </action>
- <action issue="COLLECTIONS-294" dev="bayard" type="fix" due-to="Benjamin Bentmann">
- "CaseInsensitiveMap" will now convert input strings to lower-case in a
- locale-independent manner.
- </action>
- <action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
- "MultiKey" will now be correctly serialized/de-serialized.
- </action>
- <action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
- "Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
- if the size of the map is less or equal 3.
- </action>
- <action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
- "SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
- provided index.
- </action>
- <action issue="COLLECTIONS-228" dev="scolebourne" type="fix">
- "MultiValueMap#put(Object, Object)" and "MultiValueMap#putAll(Object, Collection)"
- now correctly return if the map has changed by this operation.
- </action>
- <action issue="COLLECTIONS-219" dev="scolebourne" type="fix" due-to="Tom Leccese">
- "CollectionUtils#removeAll" wrongly called "ListUtils#retainAll".
- </action>
- <action issue="COLLECTIONS-217" dev="scolebourne" type="fix" due-to="Matt Bishop">
- Calling "setValue(Object)" on any Entry returned by a "Flat3Map" will now
- correctly set the value for the current entry.
- </action>
- </release>
- </body>
-</document>
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<document>
+ <properties>
+ <title>Apache Commons Collections Release Notes</title>
+ </properties>
+ <body>
+ <release version="4.5" date="2019-MM-DD" description="Maintenance release.">
+ <action issue="COLLECTIONS-724" dev="ggregory" type="updated." due-to="Eitan Adler">
+ Simplify two remove-if loops #77.
+ </action>
+ <action issue="COLLECTIONS-726" dev="ggregory" type="updated." due-to=" liuhaozzu, Gary Gregory">
+ Add lambdas function to provide default values in MapUtils #81.
+ </action>
+ </release>
+ <release version="4.4" date="2019-07-05" description="Maintenance release.">
+ <action issue="COLLECTIONS-710" dev="ggregory" type="fix" due-to="Yu Shi, Gary Gregory">
+ NullPointerExceptions in CompositeCollection, CompositeSet, and CompositeMap.
+ </action>
+ <action issue="COLLECTIONS-715" dev="ggregory" type="add" due-to="morningmemo, Gary Gregory">
+ Implement Collection's removeIf().
+ </action>
+ <action issue="COLLECTIONS-718" dev="ggregory" type="update" due-to="Eitan Adler">
+ Fix LRUMap exception message.
+ </action>
+ <action issue="COLLECTIONS-719" dev="ggregory" type="add" due-to="Gary Gregory">
+ Create a PropertiesFactory and SortedPropertiesFactory.
+ </action>
+ <action issue="COLLECTIONS-719" dev="ggregory" type="add" due-to="Stephan Windmüller, Bruno P. Kinoshita">
+ Support Transformer for LazyList #52.
+ </action>
+ <action issue="COLLECTIONS-723" dev="ggregory" type="add" due-to="Eitan Adler, SOC, Bruno P. Kinoshita">
+ Make use of FunctionalInterface #48.
+ </action>
+ <action issue="COLLECTIONS-716" dev="ggregory" type="update" due-to="Sebb">
+ Don't include email address in Exception messages.
+ </action>
+ </release>
+ <release version="4.3" date="2018-12-21" description="Update from Java 7 to Java 8, bug fixes, and small changes.">
+ <action issue="COLLECTIONS-691" dev="kinow" type="fix" due-to="Eitan Adler">
+ Use boolean operator for boolean result.
+ </action>
+ <action issue="COLLECTIONS-688" dev="ggregory" type="update">
+ Update platform requirement from Java 7 to 8.
+ </action>
+ <action issue="COLLECTIONS-689" dev="ggregory" type="update" due-to="Richard Walker">
+ Link to Javadoc API broken.
+ </action>
+ <action issue="COLLECTIONS-692" dev="ggregory" type="update" due-to="Gary Gregory, Eitan Adler">
+ Replace use of deprecated Class#newInstance() PR #49.
+ </action>
+ <action issue="COLLECTIONS-696" dev="ggregory" type="add" due-to="Maxim Solodovnik">
+ AbstractReferenceMap made easier for subclassing; PR #51.
+ </action>
+ <action issue="COLLECTIONS-701" dev="ggregory" type="fix" due-to="Shin Hong, Don Jeba">
+ StackOverflowError in SetUniqueList.add() when it receives itself.
+ </action>
+ <action issue="COLLECTIONS-703" dev="ggregory" type="fix" due-to="Tomas Tulka">
+ The PassiveExpiringMap#put() method should return the previous record only if not expired.
+ </action>
+ <action issue="COLLECTIONS-706" dev="ggregory" type="fix" due-to="Richard Eckart de Castilho, Gary Gregory">
+ Add SetUtils.unmodifiableSet(T... items) method.
+ </action>
+ <action issue="COLLECTIONS-709" dev="ggregory" type="fix" due-to="Robert Wertman">
+ MultiSet.Entry::getCount() isn't 0 after removing the last element.
+ </action>
+ </release>
+ <release version="4.2" date="2018-07-11" description="Update from Java 6 to Java 7, bug fixes, and small changes.">
+ <action issue="COLLECTIONS-681" dev="kinow" type="add" due-to="Stephan Fuhrmann">
+ Add test for MultiSetUtils
+ </action>
+ <action issue="COLLECTIONS-599" dev="ggregory" type="fix" due-to="Tejas Patel, Saleem Akbar, Gary Gregory">
+ HashEntry array object naming data initialized with double the size during deserialization.
+ </action>
+ <action issue="COLLECTIONS-662" dev="chtompki" type="fix" due-to="Vamsi Kavuri">
+ Unit tests MapUtilsTest and ListIteratorWrapperTest no longer fail on Java 9.
+ </action>
+ <action issue="COLLECTIONS-661" dev="kinow" type="fix">
+ Intermittent test failures in Windows for HashSetValuedHashMap.
+ </action>
+ <action issue="COLLECTIONS-660" dev="kinow" type="fix">
+ Uncomment test in AbstractMapTest regarding LRUMap equals.
+ </action>
+ <action issue="COLLECTIONS-658" dev="britter" type="add">
+ Add Automatic-Module-Name MANIFEST entry for Java 9 compatibility.
+ </action>
+ <action issue="COLLECTIONS-656" dev="ggregory" type="fix">
+ Fix site build on Java 8.
+ </action>
+ <action issue="COLLECTIONS-653" dev="kinow" type="fix">
+ Update Javadoc to Build on Java 1.8.
+ </action>
+ <action issue="COLLECTIONS-606" dev="chtompki" type="fix" due-to="Vamsi Kavuri">
+ Build status, Coverage status and Maven central weren't in README.md
+ </action>
+ <action issue="COLLECTIONS-602" dev="kinow" type="update" due-to="John Mark">
+ Improve efficiency of DefaultedMap.get.
+ </action>
+ <action issue="COLLECTIONS-603" dev="kinow" type="update" due-to="Artem Konovalov">
+ Small improvements for generics, conditional statements, and warnings suppressions.
+ </action>
+ <action issue="COLLECTIONS-655" dev="ggregory" type="update">
+ Update platform from Java 6 to Java 7.
+ </action>
+ <action issue="COLLECTIONS-594" dev="ggregory" type="fix" due-to="Javen O'Neal">
+ Web site spelling error: MultiValuedMapeList.
+ </action>
+ <action issue="COLLECTIONS-597" dev="ggregory" type="fix" due-to="Enrique">
+ Correction of Javadoc for org.apache.commons.collections4.functors.CatchAndRethrowClosure.
+ </action>
+ <action issue="COLLECTIONS-589" dev="ggregory" type="add" due-to="Gary Gregory">
+ Add null-safe MapUtils.size(Map<?, ?>) method.
+ </action>
+ <action issue="COLLECTIONS-586" dev="ggregory" type="add" due-to="Shailender Bathula, Gary Gregory">
+ PatriciaTrie prefixMap clear throws NullPointerException.
+ </action>
+ <action issue="COLLECTIONS-654" dev="ggregory" type="add">
+ Add class SortedProperties to sort keys.
+ </action>
+ <action issue="COLLECTIONS-666" dev="ggregory" type="update" due-to="BELUGA BEHR">
+ org.apache.commons.collections4.ListUtils.union(List, List) should pre-allocate result list.
+ </action>
+ <action issue="COLLECTIONS-669" dev="ggregory" type="update" due-to="BELUGA BEHR, Gary Gregory">
+ Update org.apache.commons.collections4.CollectionUtils.addAll(Collection<C>, C[]) to addAll(Collection<C>, C...).
+ </action>
+ <action issue="COLLECTIONS-668" dev="ggregory" type="add" due-to="Gary Gregory">
+ Add CollectionUtils containsAny method for primitive array: org.apache.commons.collections4.CollectionUtils.containsAny(Collection<?>, T...).
+ </action>
+ <action issue="COLLECTIONS-575" dev="ggregory" type="add" due-to="Guram Savinov, Grzegorz Rożniecki, Bruno P. Kinoshita, Gary Gregory">
+ Synchronized queue wrapper in QueueUtils.
+ </action>
+ <action issue="COLLECTIONS-670" dev="ggregory" type="add" due-to="Gary Gregory">
+ Add org.apache.commons.collections4.IteratorUtils.first(Iterator).
+ </action>
+ <action issue="COLLECTIONS-671" dev="ggregory" type="add" due-to="Gary Gregory">
+ Add org.apache.commons.collections4.IterableUtils.first(Iterable).
+ </action>
+ <action issue="COLLECTIONS-678" dev="ggregory" type="fix" due-to="Oscar Luis Vera Pérez">
+ The verification of unsupported iterator methods is not complete.
+ </action>
+ <action issue="COLLECTIONS-673" dev="ggregory" type="fix" due-to="John Mark, Stephan Fuhrmann">
+ ListUtils.partition potential integer overflow.
+ </action>
+ </release>
+ <release version="4.1" date="2015-11-28" description="This is a security and minor release.">
+ <action issue="COLLECTIONS-508" dev="tn" type="add">
+ Added new interfaces "MultiValuedMap", "ListValuedMap" and "SetValuedMap"
+ as a replacement for "MultiMap". Decorators and implementations reside in
+ the "multimap" package and a "MultiMapUtils" class has been added.
+ The existing interface "MultiMap" as well as the concrete implementation
+ "MultiValueMap" has been deprecated.
+ </action>
+ <action issue="COLLECTIONS-551" dev="tn" type="update">
+ Deprecated various method in "CollectionUtils" in favor of similar
+ methods in the newly introduced "IterableUtils".
+ </action>
+ <action issue="COLLECTIONS-580" dev="tn" type="update">
+ Serialization support for unsafe classes in the functor package
+ has been removed as this can be exploited for remote code execution
+ attacks. Classes considered to be unsafe are: CloneTransformer,
+ ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer,
+ PrototypeCloneFactory, PrototypeSerializationFactory, WhileClosure.
+ </action>
+ <action issue="COLLECTIONS-580" dev="tn" type="fix">
+ Added validation when de-serializing a "MultiValueMap#ReflectionFactory":
+ only Collection classes are allowed, otherwise an UnsupportedOperationException
+ will be thrown during de-serialization.
+ </action>
+ <action issue="COLLECTIONS-567" dev="tn" type="add">
+ Added new MultiSet interface which is intended to be a replacement for
+ the Bag interface. The main difference is that a MultiSet is fully compatible
+ to the Collection contract.
+ </action>
+ <action issue="COLLECTIONS-576" dev="tn" type="fix" due-to="Stephan Roch">
+ Subclasses of MultiKey did not re-calculate their hashcode after de-serialization.
+ </action>
+ <action issue="COLLECTIONS-572" dev="tn" type="add">
+ Added set operations to "SetUtils": union, difference, intersection and disjunction.
+ The operations return a view of the result that is backed by the input sets.
+ </action>
+ <action issue="COLLECTIONS-570" dev="tn" type="update">
+ All constructors and static factory methods will now throw a "NullPointerException" if
+ a required input argument is null. Previously sometimes a "IllegalArgumentException" was used.
+ </action>
+ <action issue="COLLECTIONS-571" dev="tn" type="update">
+ Deprecated methods "synchronizedCollection(Collection)" and "unmodifiableCollection(Collection)"
+ in class "CollectionUtils", the corresponding methods in "java.util.Collections" should be used instead.
+ </action>
+ <action issue="COLLECTIONS-566" dev="tn" type="fix">
+ "IteratorUtils#collate(...)" methods did not use natural ordering when a
+ null comparator was provided.
+ </action>
+ <action issue="COLLECTIONS-557" dev="tn" type="add" due-to="Philippe Mouawad">
+ Added support to specify the initial size of a "LRUMap".
+ </action>
+ <action issue="COLLECTIONS-565" dev="tn" type="add">
+ Added decorators for "NavigableSet" interface.
+ </action>
+ <action issue="COLLECTIONS-464,COLLECTIONS-442" dev="tn" type="add">
+ Added new class "FluentIterable" to support a fluent API for manipulating
+ Iterable instances. Additionally various supporting methods have been
+ added to "IterableUtils" and "IteratorUtils".
+ </action>
+ <action issue="COLLECTIONS-464" dev="tn" type="add">
+ Added new "ZippingIterator" and factory methods "IteratorUtils#zippingIterator(...)".
+ </action>
+ <action issue="COLLECTIONS-464" dev="tn" type="add">
+ Added new decorator "SkippingIterator" and factory methods "IteratorUtils#skippingIterator(...)".
+ </action>
+ <action issue="COLLECTIONS-556" dev="tn" type="add">
+ Added method "SetUtils#newIdentityHashSet()" which returns a new identity HashSet
+ using reference-equality instead of object-equality.
+ </action>
+ <action issue="COLLECTIONS-562" dev="tn" type="update">
+ Upgraded minimum java requirement to Java 6 (up from Java 5).
+ </action>
+ <action issue="COLLECTIONS-395" dev="tn" type="add" due-to="David Hawthorne">
+ Added method "LRUMap#get(Object, boolean)" that allows to query the map
+ without affecting the least recently used order.
+ </action>
+ <action issue="COLLECTIONS-558" dev="tn" type="fix" due-to="Felix Rabe">
+ Changed return type of "ListOrderedSet#remove(int)" from Object to the generic type parameter.
+ </action>
+ <action issue="COLLECTIONS-555" dev="tn" type="fix" due-to="M Kim">
+ Added clarification to javadoc of "TreeBag#add(Object)" wrt null arguments.
+ </action>
+ <action issue="COLLECTIONS-427" dev="tn" type="add" due-to="Gonçalo Marques">
+ Added "toString(...)" methods to newly created "IterableUtils" and existing "IteratorUtils"
+ to get a string representation of an Iterable/Iterator instance similar to "Arrays#toString(...)".
+ </action>
+ <action issue="COLLECTIONS-427" dev="tn" type="fix">
+ Reverted performance improvement for "SetUniqueList#retainAll(Collection)"
+ introduced in 4.0. Added clarifying javadoc wrt runtime complexity instead.
+ </action>
+ <action issue="COLLECTIONS-426" dev="tn" type="fix">
+ Reverted performance improvement for "ListOrderedSet#retainAll(Collection)"
+ introduced in 4.0. Added clarifying javadoc wrt runtime complexity instead.
+ </action>
+ <action issue="COLLECTIONS-530" dev="tn" type="fix" due-to="Erik">
+ Added a Builder for "PredicatedCollection". Elements added to the builder
+ that fail the predicate will not throw an IllegalArgumentException. The builder
+ supports creating predicated lists, bags, sets and queues.
+ </action>
+ <action issue="COLLECTIONS-545" dev="tn" type="fix" due-to="Oswaldo Olivo">
+ Documented runtime complexity of "CollectionUtils#removeAll(Collection, Collection).
+ </action>
+ <action issue="COLLECTIONS-543" dev="tn" type="fix">
+ "AbstractCollectionDecorator" doesn't forward equals and hashCode anymore.
+ </action>
+ <action issue="COLLECTIONS-544" dev="tn" type="fix" due-to="Oswaldo Olivo">
+ Documented runtime complexity of "CollectionUtils#retainAll(Collection, Collection).
+ </action>
+ <action issue="COLLECTIONS-542" dev="tn" type="fix">
+ "AbstractHashedMap" still inherits from "AbstractMap", contrary to what
+ the class javadoc stated. The inheritance will now be removed in v5.0.
+ </action>
+ <action issue="COLLECTIONS-539" dev="tn" type="add" due-to="Guram Savinov">
+ Changed scope of "CircularFifoQueue#isAtFullCapacity()" to public.
+ </action>
+ <action issue="COLLECTIONS-525" dev="tn" type="fix" due-to="Zigler Zhang">
+ The map returned by "PatriciaTrie#prefixMap()" did not contain all keys
+ that are prefixed by the given search key in some rare cases.
+ </action>
+ <action issue="COLLECTIONS-511" dev="tn" type="add" due-to="Nathan Blomquist, Brent Worden">
+ Added new methods "IterableUtils#partition(...)" to partition an input collection
+ into separate output collections based on evaluation of one or more predicates.
+ </action>
+ <action issue="COLLECTIONS-537" dev="tn" type="fix" due-to="Frank Jakop">
+ Harmonized signature of factory methods for functor-related classes which take
+ a collection as input with their array counterparts.
+ </action>
+ <action issue="COLLECTIONS-540" dev="tn" type="fix" due-to="Daniel Stewart, Issam El Atif">
+ Added overloaded method "CollectionUtils#get(Enumeration, int)" and simplified
+ code for "CollectionUtils#get(Object, int)".
+ </action>
+ <action issue="COLLECTIONS-536" dev="tn" type="fix" due-to="Tagir Valeev">
+ Improved check for null input in "MapUtils#putAll(Map, Object[])".
+ </action>
+ <action issue="COLLECTIONS-534" dev="tn" type="fix" due-to="Oswaldo Olivo">
+ Added clarifying javadoc wrt runtime complexity of "CollectionBag#retainAll".
+ </action>
+ <action issue="COLLECTIONS-529" dev="tn" type="add" due-to="Alexander Muthmann, Dipanjan Laha">
+ Added methods "removeAll(...)" and "retainAll(...)" to "CollectionUtils" that perform
+ equality checks using the provided "Equator" object instead of "Object#equals()".
+ </action>
+ <action issue="COLLECTIONS-531" dev="tn" type="fix" due-to="Dipanjan Laha">
+ Use correct type bounds in
+ "CollectionUtils#isEqualCollection(Collection, Collection, Equator)" to
+ prevent a "ClassCastException" at runtime for invalid inputs.
+ </action>
+ <action issue="COLLECTIONS-523" dev="tn" type="fix" due-to="Thiago Andrade">
+ Removed unneeded private method in "PassiveExpiringMap".
+ </action>
+ <action issue="COLLECTIONS-516" dev="tn" type="fix" due-to="Cyrille Artho">
+ Added clarification to the javadoc of "MapUtils#toProperties(Map)" in case
+ of null keys/values.
+ </action>
+ <action issue="COLLECTIONS-524" dev="tn" type="fix" due-to="J Goodfellow">
+ "ListOrderedSet#listOrderedSet(List)" did not remove duplicates from the
+ input list as advertised in the javadoc.
+ </action>
+ <action issue="COLLECTIONS-521" dev="tn" type="fix" due-to="Maxime Nay">
+ "MultiKeyMap" was throwing a "NullPointerException" for various operations
+ if two key arguments have been used and the second was "null".
+ </action>
+ <action issue="COLLECTIONS-522" dev="tn" type="fix" due-to="Erik">
+ Updated code example for "PredicatedList".
+ </action>
+ <action issue="COLLECTIONS-512" dev="tn" type="fix" due-to="Cyrille Artho">
+ "TransformingComparator" and "FixedOrderComparator" did not comply with
+ the contract of "Object#equals".
+ </action>
+ <action issue="COLLECTIONS-510" dev="tn" type="fix" due-to="Hollis Waite">
+ Fix compilation errors when using source level 1.8 and a recent java 8 compiler.
+ </action>
+ <action issue="COLLECTIONS-509" dev="tn" type="fix">
+ Clarified javadoc of "CollectionBag" wrt changes from the original Bag interface.
+ </action>
+ <action issue="COLLECTIONS-507" dev="tn" type="fix" due-to="Gerson">
+ Removed wrong type bounds for "ComparatorUtils#chainedComparator(...)".
+ </action>
+ <action issue="COLLECTIONS-506" dev="tn" type="fix" due-to="Anthony Communier">
+ Added javadoc clarification to class "CollectionUtils" that input objects which
+ override "Object#equals(Object)" must also maintain the general contract of
+ "Object#hashCode()" as various utility methods take advantage of sets/maps/bags.
+ </action>
+ <action issue="COLLECTIONS-503" dev="tn" type="add" due-to="Josh Cain">
+ Added new transformer "IfTransformer" and factory methods "TransformerUtils#ifTransformer(...)"
+ which replace "TransformerUtils#switchTransformer(Predicate, Transformer, Transformer)".
+ </action>
+ <action issue="COLLECTIONS-471" dev="tn" type="add" due-to="Radford Tam">
+ Added new decorator "BoundedIterator" and factory methods "IteratorUtils#boundedIterator(...)".
+ </action>
+ </release>
+ <release version="4.0" date="2013-11-27" description="
+This is a major release: It combines bug fixes, new features and
+changes to existing features.
+
+Most notable changes are: use of generics and other language features introduced in Java 5 (varargs, Iterable),
+removed deprecated classes / methods and features which are now supported by the JDK,
+replaced Buffer interface with java.util.Queue,
+added concept of split maps with respective interfaces Put / Get (see also package splitmap),
+added new Trie interface together with an implementation of a Patricia Trie.
+
+Because of the base package name change, this release can be used together
+with earlier versions of Commons Collections.
+The minimal version of the Java platform required to compile and use
+Commons Collections is Java 5.
+Users are encouraged to upgrade to this version as, in addition to new
+features, this release includes numerous bug fixes.
+ ">
+ <action issue="COLLECTIONS-502" dev="tn" type="update">
+ Resolved generic parameter inconsistency for various static fields, e.g. BagUtils.EMPTY_BAG,
+ TruePredicate.INSTANCE and many others. All accessible static fields use raw types so that
+ they can be used directly without explicit casting. To avoid compiler warnings about unchecked
+ conversion and/or rawtypes use the corresponding factory methods, e.g. BagUtils.emptyBag().
+ </action>
+ <action issue="COLLECTIONS-501" dev="tn" type="update">
+ Renamed methods "V MultiKeyMap#remove(Object, Object, ...)" to
+ "V MultiKeyMap#removeMultiKey(Object, Object, ...)" to avoid future conflicts
+ with a default method of the Map interface in Java 8.
+ </action>
+ <action issue="COLLECTIONS-500" dev="tn" type="update">
+ Renamed "V MultiMap#remove(K, V)" to "boolean MultiMap#removeMapping(K, V)"
+ to avoid future conflicts with a default method of the Map interface in Java 8.
+ </action>
+ <action issue="COLLECTIONS-499" dev="tn" type="update">
+ Refactored the test framework for Bag implementations to extend from
+ "AbstractCollectionTest" by decorating the concrete Bag instance with
+ a CollectionBag or CollectionSortedBag.
+ </action>
+ <action issue="COLLECTIONS-498" dev="tn" type="fix">
+ "CollectionBag" will now also respect the contract of the decorated bag in case
+ a null argument is provided to either removeAll or retainAll.
+ </action>
+ <action issue="COLLECTIONS-497" dev="tn" type="add">
+ Added bag decorator "CollectionSortedBag" which decorates a SortedBag to make it
+ comply with the Collection contract.
+ </action>
+ <action issue="COLLECTIONS-496" dev="tn" type="update">
+ "UnmodifiableBoundedCollection" does now also implement the marker interface "Unmodifiable"
+ similar as all other unmodifiable decorators.
+ </action>
+ <action issue="COLLECTIONS-495" dev="tn" type="fix">
+ "UnmodifiableTrie#unmodifiableTrie(Trie)" will not decorate again an already
+ unmodifiable Trie. Also the return type has been changed to "Trie" to be consistent
+ with other Unmodifiable decorators.
+ </action>
+ <action issue="COLLECTIONS-494" dev="tn" type="update" due-to="Emmanuel Bourg">
+ Moved "Equator" interface to base package for consistency.
+ </action>
+ <action issue="COLLECTIONS-488" dev="tn" type="add" due-to="Josh Cain">
+ Added "CollectionsUtils#matchesAll(Iterable, Predicate)" to test if all elements
+ of a collection match a given predicate.
+ </action>
+ <action issue="COLLECTIONS-485" dev="tn" type="fix" due-to="Hollis Waite">
+ Accept wildcard input where possible, e.g. in copy-constructors, Unmodifiable* decorators
+ and iterators.
+ </action>
+ <action issue="COLLECTIONS-481" dev="tn" type="fix" due-to="Hollis Waite">
+ No collision detection/resolution was performed when calling "CompositeSet#addComposited(...)"
+ with more than one Set as argument. Additionally use varargs parameters instead of arrays
+ in CompositeSet and CompositeCollection constructor and addComposited method.
+ </action>
+ <action issue="COLLECTIONS-480" dev="tn" type="update" due-to="Hollis Waite">
+ Narrow return type of "BidiMap#values()" to Set as the values are required to be unique.
+ </action>
+ <action issue="COLLECTIONS-475" dev="tn" type="fix">
+ Fixed conversion of timeout parameters in "PassiveExpiringMap".
+ </action>
+ <action issue="COLLECTIONS-474" dev="sebb" type="fix" due-to="Ning Chen">
+ Exception in "ListOrderedMap#putAll" if map contains null values.
+ </action>
+ <action issue="COLLECTIONS-473" dev="tn" type="update" due-to="sebb">
+ Made field "collection" in class "AbstractCollectionDecorator" private and added
+ setter "setCollection(Collection)" with scope protected to set the decorated collection
+ during de-serialization.
+ </action>
+ <action issue="COLLECTIONS-472" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "AbstractMapBag#containsAll(Collection)" by returning immediately
+ after a difference has been found.
+ </action>
+ <action issue="COLLECTIONS-470" dev="tn" type="update" due-to="sebb">
+ Renamed class "TransformedMap" in package "splitmap" to "TransformedSplitMap" to avoid
+ name clash with similar class in package "map".
+ </action>
+ <action issue="COLLECTIONS-468" dev="tn" type="add">
+ Added bag decorator "CollectionBag" which decorates a bag to make it comply with the
+ Collection contract.
+ </action>
+ <action issue="COLLECTIONS-466" dev="tn" type="update">
+ Replaced "Collection" with "Iterable" for method arguments where applicable.
+ </action>
+ <action issue="COLLECTIONS-463" dev="tn" type="add" due-to="Andy Seaborne, Claude Warren">
+ Added "PushbackIterator" decorator to support pushback of elements during iteration.
+ </action>
+ <action issue="COLLECTIONS-462" dev="tn" type="add" due-to="Andy Seaborne, Claude Warren">
+ Added "PeekingIterator" decorator to support one-element lookahead during iteration.
+ </action>
+ <action issue="COLLECTIONS-461" dev="tn" type="fix" due-to="Matt Benson, sebb">
+ Added additional clarification to javadoc of interface "Put" wrt return type of
+ "put(Object, Object)" method.
+ </action>
+ <action issue="COLLECTIONS-460" dev="tn" type="update">
+ Changed "IteratorChain" to use internally a "Queue" instead of a "List". Iterators are
+ removed from the queue once used and can be garbage collected after being exhausted.
+ Additionally removed the methods "setIterator(Iterator)" and "getIterators()".
+ </action>
+ <action issue="COLLECTIONS-459" dev="tn" type="update" due-to="sebb">
+ Removed method "setArray(Object)" in class ArrayIterator and method "setArray(Object[])"
+ in class ObjectArrayIterator and made fields array, startIndex and endIndex final.
+ </action>
+ <action issue="COLLECTIONS-458" dev="sebb" type="remove">
+ Removed unused class "AbstractUntypedCollectionDecorator<E, D>".
+ </action>
+ <action issue="COLLECTIONS-456" dev="tn" type="add">
+ Added methods "ListUtils#longestCommonSubsequence(...)" to get the longest common subsequence
+ of arbitrary lists or CharSequences.
+ </action>
+ <action issue="COLLECTIONS-455" dev="sebb" type="update">
+ Changed scope of fields to private where appropriate.
+ </action>
+ <action issue="COLLECTIONS-454" dev="tn" type="update">
+ An iterator over a "Flat3Map#entrySet()" will now return
+ independent Map.Entry objects that will not change anymore when
+ the iterator progresses.
+ </action>
+ <action issue="COLLECTIONS-453" dev="tn" type="update">
+ Several closure and transformer implementations in the functors package
+ will now copy an array as input to their constructor (e.g. ChainedClosure).
+ </action>
+ <action issue="COLLECTIONS-452" dev="tn" type="update">
+ Change base package to org.apache.commons.collections4.
+ </action>
+ <action issue="COLLECTIONS-451" dev="tn" type="update">
+ The constructors for all Utils classes are now private to prevent instantiation.
+ </action>
+ <action issue="COLLECTIONS-450" dev="tn" type="add" due-to="J. Moldawski">
+ Added methods "forAllButLastDo(Collection, Closure)" and "forAllButLastDo(Iterator, Closure)"
+ to class "CollectionUtils".
+ </action>
+ <action issue="COLLECTIONS-447" dev="tn" type="fix" due-to="Jeffrey Barnes">
+ Tree traversal with a TreeListIterator will not be affected anymore by
+ the removal of an element directly after a call to previous().
+ </action>
+ <action issue="COLLECTIONS-446" dev="tn" type="add" due-to="Matt Lachman">
+ Added method "CollectionUtils#isEqualCollection(Collection, Collection, Equator)".
+ </action>
+ <action issue="COLLECTIONS-445" dev="tn" type="fix">
+ Adapt and/or ignore several unit tests when run on a IBM J9 VM (specification version 1.6.0)
+ due to a faulty "java.util.TreeMap" implementation.
+ </action>
+ <action issue="COLLECTIONS-444" dev="tn" type="fix" due-to="Thomas Vahrst, John Vasileff">
+ SetUniqueList.set(int, E) now works correctly if the object to be inserted
+ is already placed at the given position.
+ </action>
+ <action issue="COLLECTIONS-441" dev="tn" type="fix" due-to="Thomas Vahrst">
+ MultiKeyMap.clone() now correctly calls super.clone().
+ </action>
+ <action issue="COLLECTIONS-436" dev="tn" type="add" due-to="Arman Sharif">
+ Added "emptyIfNull" methods to classes "CollectionUtils", "ListUtils", "SetUtils"
+ and "MapUtils".
+ </action>
+ <action issue="COLLECTIONS-433" dev="tn" type="fix" due-to="Jeffrey Barnes">
+ Improve performance of "TreeList#addAll" and "TreeList(Collection)" by converting
+ the input collection into an AVL tree and efficiently merge it into the existing tree.
+ </action>
+ <action issue="COLLECTIONS-432" dev="tn" type="update">
+ Replaced "Buffer" interface with "java.util.Queue". Kept "CircularFifoQueue"
+ as well as "Predicated", "Transformed" and "Unmodifiable" decorators.
+ </action>
+ <action issue="COLLECTIONS-429,COLLECTIONS-434" dev="tn" type="add" due-to="Adrian Nistor, Mert Guldur">
+ Added method "CollectionUtils#containsAll(Collection, Collection)" with guaranteed
+ runtime complexity of O(n + m) and space complexity of O(n). This method may yield much
+ better performance than "Collection#containsAll(Collection)" depending on the use-case and
+ type of collection used.
+ </action>
+ <action issue="COLLECTIONS-427" dev="brentworden" type="fix" due-to="Mert Guldur">
+ Fixed performance issue in "SetUniqueList#retainAll" method for large collections.
+ </action>
+ <action issue="COLLECTIONS-426" dev="brentworden" type="fix" due-to="Adrian Nistor">
+ Fixed performance issue in "ListOrderedSet#retainAll" method for large collections.
+ </action>
+ <action issue="COLLECTIONS-425" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "ListOrderedMap#remove(Object)" method.
+ </action>
+ <action issue="COLLECTIONS-424" dev="tn" type="update" due-to="Michael Pradel">
+ "CompositeSet" does not inherit from "CompositeCollection" anymore. The inner class
+ "SetMutator" has been updated accordingly.
+ </action>
+ <action issue="COLLECTIONS-422" dev="tn" type="add" due-to="Benoit Corne">
+ Added method "CollectionUtils#permutations(Collection)" and class "PermutationIterator"
+ to generate unordered permutations of a collection.
+ </action>
+ <action issue="COLLECTIONS-421" dev="tn" type="fix" due-to="Benedikt Ritter">
+ Update javadoc for "ListUtils#lazyList()" and "ListUtils#fixedSizeList()".
+ </action>
+ <action issue="COLLECTIONS-419" dev="tn" type="fix" due-to="Adrian Nistor">
+ Added clarifying javadoc wrt runtime complexity of "AbstractDualBidiMap#retainAll".
+ </action>
+ <action issue="COLLECTIONS-417" dev="tn" type="fix" due-to="Adrian Nistor">
+ Added clarifying javadoc wrt runtime complexity of "AbstractLinkedList#retainAll".
+ </action>
+ <action issue="COLLECTIONS-415" dev="tn" type="fix" due-to="Adrian Nistor">
+ Added clarifying javadoc wrt runtime complexity of "AbstractLinkedList#removeAll".
+ </action>
+ <action issue="COLLECTIONS-414" dev="tn" type="fix">
+ Fixed several compilation issues with older Java 1.6 compilers.
+ </action>
+ <action issue="COLLECTIONS-413" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "removeAll()" method for sets returned by "DualHashBidiMap#entrySet()".
+ </action>
+ <action issue="COLLECTIONS-412" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "CollectionUtils#subtract" methods.
+ </action>
+ <action issue="COLLECTIONS-411" dev="tn" type="fix" due-to="Adrian Nistor">
+ Fixed possible "IndexOutOfBoundsException" in "ListOrderedMap#putAll".
+ </action>
+ <action issue="COLLECTIONS-410" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "SetUniqueList#addAll" method.
+ </action>
+ <action issue="COLLECTIONS-409" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "ListOrderedSet#addAll" method.
+ </action>
+ <action issue="COLLECTIONS-408" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "SetUniqueList#removeAll".
+ </action>
+ <action issue="COLLECTIONS-407" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "ListOrderedSet#remove(Object)" in case the object is
+ not contained in the Set.
+ </action>
+ <action issue="COLLECTIONS-406" dev="tn" type="fix" due-to="Adrian Nistor">
+ Improved performance of "ListUtils#subtract" method.
+ </action>
+ <action issue="COLLECTIONS-405" dev="brentworden" type="add" due-to="Adam Dyga">
+ Added "ListUtils#select" and "ListUtils#selectRejected" methods.
+ </action>
+ <action issue="COLLECTIONS-404" dev="luc" type="add" due-to="Jordane Sarda">
+ Added an implementation of Eugene Myers difference algorithm in package
+ o.a.c.c.sequence.
+ </action>
+ <action issue="COLLECTIONS-400" dev="tn" type="fix" due-to="Shin Hwei Tan">
+ Added missing null check in "CollectionUtils#addIgnoreNull(Collection, Object)".
+ </action>
+ <action issue="COLLECTIONS-399" dev="tn" type="add" due-to="Sebb">
+ Added new method "get(int)" to "CircularFifoQueue".
+ </action>
+ <action issue="COLLECTIONS-396" dev="tn" type="add" due-to="Jeff Rodriguez">
+ Added "LazyIteratorChain" iterator.
+ </action>
+ <action issue="COLLECTIONS-393" dev="tn" type="add" due-to="Chris Shayan">
+ Added "ListUtils#partition" method to split a List into consecutive sublists.
+ </action>
+ <action issue="COLLECTIONS-391" dev="tn" type="fix" due-to="Shin Hwei Tan">
+ Fixed javadoc for "MapUtils#toProperties(Map)".
+ </action>
+ <action issue="COLLECTIONS-389" dev="tn" type="fix" due-to="Shin Hwei Tan">
+ Clarified javadoc for "TransformerUtils#mapTransformer" for null input.
+ </action>
+ <action issue="COLLECTIONS-388" dev="tn" type="fix" due-to="Shin Hwei Tan">
+ Clarified javadoc for "FactoryUtils#prototypeFactory" for null input.
+ </action>
+ <action issue="COLLECTIONS-384" dev="ggregory" type="fix" due-to="Shin Hwei Tan">
+ Fixed inconsistent javadoc for "MapUtils#synchronizedMap(Map)".
+ </action>
+ <action issue="COLLECTIONS-383" dev="tn" type="add" due-to="Adrian Cumiskey">
+ Added "CollectionUtils#forAllDo" implementation which takes an "Iterator" as input.
+ </action>
+ <action issue="COLLECTIONS-382" dev="tn" type="update" due-to="Olivier Lamy">
+ Change maven coordinates to "org.apache.commons.commons-collections4".
+ </action>
+ <action issue="COLLECTIONS-381" dev="sebb" type="update" due-to="Olivier Lamy">
+ Move the project structure to a standard maven layout.
+ </action>
+ <action issue="COLLECTIONS-380" dev="tn" type="fix" due-to="Dave Brosius">
+ Fixed infinite loop when calling "UnmodifiableBoundedCollection#unmodifiableBoundedCollection()".
+ </action>
+ <action issue="COLLECTIONS-379" dev="tn" type="fix" due-to="Shin Hwei Tan">
+ Fixed javadoc for several methods wrt expected NullPointerExceptions.
+ </action>
+ <action issue="COLLECTIONS-375" dev="tn" type="add" due-to="Ivan Hristov">
+ Added method "ListUtils#defaultIfNull(List, List)".
+ </action>
+ <action issue="COLLECTIONS-372" dev="tn" type="update">
+ TransformingComparator now supports different types for its input/output values.
+ </action>
+ <action issue="COLLECTIONS-364" dev="sebb" type="fix">
+ "DualTreeBidiMap" now uses the correct comparator for the reverse map during de-serialization.
+ </action>
+ <action issue="COLLECTIONS-363" dev="sebb" type="fix">
+ "TransformedMap" in the package "splitmap" can now be serialized.
+ </action>
+ <action issue="COLLECTIONS-362" dev="brentworden" type="update" due-to="Jean-Noel Rouvignac">
+ "CollectionUtils#filter(Iterable, Predicate)" will now return whether the collection
+ has been modified.
+ </action>
+ <action issue="COLLECTIONS-361" dev="tn" type="add" due-to="Jean-Noel Rouvignac">
+ Add method "CollectionUtils#filterInverse(Iterable, Predicate)".
+ </action>
+ <action issue="COLLECTIONS-360" dev="jochen" type="fix" due-to="Sai Zhang">
+ "FilterListIterator#hasNext" does not throw a NullPointerException anymore
+ to comply to the Java iterator specification.
+ </action>
+ <action issue="COLLECTIONS-359" dev="bayard" type="fix" due-to="Mark Shead">
+ "ListUtils#intersection(List, List)" will now also work correctly if there
+ are duplicate elements in the provided lists.
+ </action>
+ <action issue="COLLECTIONS-352" dev="bayard" type="fix" due-to="Adam Gent">
+ "AbstractCollectionDecorator" will now use internally "decorated()" to access
+ the decorated collection.
+ </action>
+ <action issue="COLLECTIONS-351" dev="bayard" type="remove" due-to="Henri Yandell">
+ Removed features which are now supported by the JDK.
+ </action>
+ <action issue="COLLECTIONS-350" dev="bayard" type="fix" due-to="Michael Akerman">
+ Removed debug output in "MapUtils#getNumber(Map)".
+ </action>
+ <action issue="COLLECTIONS-348" dev="brentworden" type="fix" due-to="Paul Benedict">
+ Fixed javadoc for all "transformedXXX(XXX)" methods in the respective Utils classes
+ to clarify that existing objects in the list are not transformed.
+ </action>
+ <action issue="COLLECTIONS-343" dev="mbenson" type="fix" due-to="Goran Hacek">
+ Singleton classes in package "functors" are now correctly de-serialized.
+ </action>
+ <action issue="COLLECTIONS-341" dev="mbenson" type="update" due-to="Goran Hacek">
+ "NOPClosure" is now a final class.
+ </action>
+ <action issue="COLLECTIONS-340" dev="mbenson" type="fix" due-to="Goran Hacek">
+ Removed broken methods "equals(Object)" and "hashCode()" in class "NOPClosure".
+ </action>
+ <action issue="COLLECTIONS-336" dev="bayard" type="fix" due-to="sebb">
+ Simplified exceptions as the cause is available from the parent.
+ </action>
+ <action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
+ Fixed cache assignment for "TreeBidiMap#entrySet".
+ </action>
+ <action issue="COLLECTIONS-334" dev="jochen" type="fix" due-to="sebb">
+ Synchronized access to lock in "StaticBucketMap#size()".
+ </action>
+ <action issue="COLLECTIONS-332" dev="jochen" type="fix" due-to="Tom Parker">
+ Added clarification to javadoc of "ListOrderedMap" that "IdentityMap" and
+ "CaseInsensitiveMap" are not supported.
+ </action>
+ <action issue="COLLECTIONS-331" dev="jochen" type="fix" due-to="Michael Krkoska">
+ Improve javadoc of "CollatingIterator" wrt the used "Comparator" and throw a
+ NullPointerException in "CollatingIterator#least" if no comparator is set.
+ </action>
+ <action issue="COLLECTIONS-330" dev="mbenson" type="fix" due-to="Joerg Schaible">
+ "LRUMap#keySet()#remove(Object)" will not throw a "ConcurrentModificationException" anymore.
+ </action>
+ <action issue="COLLECTIONS-328" dev="bayard" type="fix" due-to="Thomas Rogan, Jilles van Gurp">
+ Improved performance of "ListUtils#intersection(List, List)".
+ </action>
+ <action issue="COLLECTIONS-327" dev="brentworden" type="add" due-to="sebb">
+ Added serialVersionUID fields for "CompositeCollection", "CompositeSet",
+ "EmptyMapMutator", "EmptySetMutator".
+ </action>
+ <action issue="COLLECTIONS-324" dev="tn" type="update" due-to="sebb">
+ Fields transformer and decorated in class "TransformingComparator" are now final.
+ </action>
+ <action issue="COLLECTIONS-323" dev="jochen" type="fix" due-to="Maarten Brak">
+ Changed behavior of "CaseInsensitiveMap" constructor to be compliant with "HashMap"
+ in case the initial capacity is set to zero.
+ </action>
+ <action issue="COLLECTIONS-322" dev="tn" type="add" due-to="Thomas Vahrst">
+ Added NodeListIterator and convenience methods in IteratorUtils to iterate over
+ a org.w3c.dom.NodeList.
+ </action>
+ <action issue="COLLECTIONS-320" dev="bayard" type="fix" due-to="sebb">
+ Improved performance of "StaticBucketMap#putAll(Map)" by iterating over the entry set.
+ </action>
+ <action issue="COLLECTIONS-319" dev="bayard" type="fix" due-to="sebb">
+ Avoid redundant null check in "IteratorUtils#getIterator(Object)".
+ </action>
+ <action issue="COLLECTIONS-317" dev="bayard" type="fix" due-to="sebb">
+ Use a private method to populate the object in "AbstractHashedMap(Map)".
+ </action>
+ <action issue="COLLECTIONS-316" dev="bayard" type="fix" due-to="ori">
+ Fixed javadoc of "LRUMap" wrt to the maxSize parameter of the constructor.
+ </action>
+ <action issue="COLLECTIONS-313" dev="brentworden" type="add" due-to="David J. M. Karlsen">
+ Added new abstract class "CatchAndRethrowClosure" that re-throws any checked exception
+ as unchecked "FunctorException".
+ </action>
+ <action issue="COLLECTIONS-312" dev="tn" type="fix" due-to="Peter Lawrey, Gary Gregory">
+ Use of final keyword where applicable, minor performance improvements by properly
+ initializing the capacity of newly created collections when known in advance.
+ </action>
+ <action issue="COLLECTIONS-307" dev="tn" type="update" due-to="Christian Semrau, Thomas Vahrst">
+ "SetUniqueList#subList()" will now return an unmodifiable list as changes to it
+ may invalidate the parent list.
+ </action>
+ <action issue="COLLECTIONS-307" dev="bayard" type="fix" due-to="Christian Semrau">
+ "SetUniqueList#subList()#contains(Object)" will now correctly check the subList
+ rather than the parent list.
+ </action>
+ <action issue="COLLECTIONS-306" dev="brentworden" type="add" due-to="Chris Shayan">
+ Added method "CollectionUtils#subtract(Iterable, Iterable, Predicate)".
+ </action>
+ <action issue="COLLECTIONS-304" dev="bayard" type="fix" due-to="Rafał Figas,Bjorn Townsend">
+ "SetUniqueList#set(int, Object)" will now correctly enforce the uniqueness constraint.
+ </action>
+ <action issue="COLLECTIONS-303" dev="bayard" type="fix" due-to="Emmanuel Bourg">
+ Improved javadoc for "Unmodifiable*" classes wrt behavior when the users tries
+ to modify the collection.
+ </action>
+ <action issue="COLLECTIONS-298" dev="bayard" type="update" due-to="Benjamin Bentmann">
+ Calling "CollectionUtils#sizeIsEmpty(null)" will now return true.
+ </action>
+ <action issue="COLLECTIONS-296" dev="tn" type="add" due-to="Julius Davies">
+ Added methods "CollectionUtils#collate(...)" to merge two sorted Collections
+ into a sorted List using the standard O(n) merge algorithm.
+ </action>
+ <action issue="COLLECTIONS-294" dev="bayard" type="fix" due-to="Benjamin Bentmann">
+ "CaseInsensitiveMap" will now convert input strings to lower-case in a
+ locale-independant manner.
+ </action>
+ <action issue="COLLECTIONS-293" dev="tn" type="add" due-to="Stephen Kestle">
+ Added support for using custom "Equator" objects in "EqualPredicate".
+ </action>
+ <action issue="COLLECTIONS-289" dev="bayard" type="add" due-to="Fredrik Kjellberg">
+ Added method "CollatingIterator#getIteratorIndex()".
+ </action>
+ <action issue="COLLECTIONS-256,COLLECTIONS-288" dev="bayard" type="fix" due-to="Paul Benedict">
+ Fixed javadoc for "ListUtils#transformedList(List)" to clarify that existing objects
+ in the list are not transformed.
+ </action>
+ <action issue="COLLECTIONS-286" dev="mbenson" type="add" due-to="Geoffrey De Smet">
+ Added method "CollectionUtils#extractSingleton(Collection)".
+ </action>
+ <action issue="COLLECTIONS-285" dev="tn" type="add" due-to="Christian Gruenberg">
+ Added serialization support for "TreeBidiMap".
+ </action>
+ <action issue="COLLECTIONS-280" dev="bayard" type="update" due-to="Chris Lewis">
+ The predicate that rejected an object to be added to a "PredicatedCollection"
+ is now contained in the respective exception message.
+ </action>
+ <action issue="COLLECTIONS-275" dev="tn" type="add" due-to="Stephen Kestle">
+ Added "IndexedCollection" collection decorator which provides a map-like
+ view on an existing collection.
+ </action>
+ <action issue="COLLECTIONS-272" dev="tn" type="add" due-to="Chaitanya Mutyala">
+ Added serialization support for "FixedOrderComparator" and "TransformingComparator".
+ </action>
+ <action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
+ "MultiKey" will now be correctly serialized/de-serialized.
+ </action>
+ <action issue="COLLECTIONS-265" dev="bayard" type="update" due-to="David Saff">
+ "TreeBag" will now only accept "Comparable" objects as input when used with natural ordering.
+ </action>
+ <action issue="COLLECTIONS-263" dev="tn" type="add" due-to="John Hunsley">
+ Added methods "MapUtils#populateMap(MultiMap, ...)" to support also "MultiMap" instances
+ as input.
+ </action>
+ <action issue="COLLECTIONS-262" dev="bayard" type="fix" due-to="Lisen Mu">
+ Fixed javadoc for methods "firstKey()" and "lastKey()" in class "AbstractLinkedMap".
+ </action>
+ <action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
+ "Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
+ if the size of the map is less or equal 3.
+ </action>
+ <action issue="COLLECTIONS-260" dev="mbenson" type="add" due-to="Stephen Kestle">
+ Added constructor "TransformingComparator(Transformer)".
+ </action>
+ <action issue="COLLECTIONS-258" dev="tn" type="add" due-to="Nathan Blomquist">
+ Added "DualLinkedHashBidiMap" bidi map implementation.
+ </action>
+ <action issue="COLLECTIONS-255" dev="mbenson" type="fix" due-to="Henri Yandell">
+ Removed unused variables in "TreeBidiMap".
+ </action>
+ <action issue="COLLECTIONS-251,COLLECTIONS-321" dev="mbenson" type="update" due-to="Stephen Kestle">
+ The static factory methods have been renamed from "getInstance()" to a camel-case
+ version of the class name, e.g. "truePredicate()" for class "TruePredicate".
+ </action>
+ <action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
+ "SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
+ provided index.
+ </action>
+ <action issue="COLLECTIONS-242" dev="skestle" type="add">
+ Added "Equator" interface.
+ </action>
+ <action issue="COLLECTIONS-241" dev="brentworden" type="add" due-to="Elifarley Callado Coelho">
+ Added "PassiveExpiringMap" map decorator.
+ </action>
+ <action issue="COLLECTIONS-240" dev="bayard" type="update" due-to="Wouter de Vaal">
+ "MultiValueMap" is now serializable.
+ </action>
+ <action issue="COLLECTIONS-237" dev="tn" type="add" due-to="Nils Kaiser, Alan Mehlo">
+ Added method "MultiValueMap#iterator()" to return a flattened version of
+ "entrySet().iterator()". Clarified javadoc for "entrySet()" that the returned Entry
+ objects are unflattened, i.e. the Entry object for a given key contains all values
+ mapped to this key.
+ </action>
+ <action issue="COLLECTIONS-235" dev="bayard" type="add" due-to="Nathan Egge">
+ Added method "ListUtils#indexOf(List, Predicate)".
+ </action>
+ <action issue="COLLECTIONS-232" dev="bayard" type="fix" due-to="Mark Hindess">
+ Fixed several unit tests which were using parameters to "assertEquals(...)" in wrong order.
+ </action>
+ <action issue="COLLECTIONS-231" dev="tn" type="update" due-to="Torsten Curdt">
+ Return concrete class in static factory methods instead of base class interface
+ (except for Unmodifiable decorators).
+ </action>
+ <action issue="COLLECTIONS-230,COLLECTIONS-297,COLLECTIONS-318" dev="bayard" type="update" due-to="Stepan Koltsov,sebb">
+ "CollectionUtils#size(Collection)" now returns 0 when called with null as input.
+ </action>
+ <action issue="COLLECTIONS-229" dev="scolebourne" type="remove">
+ Removed deprecated classes and methods.
+ </action>
+ <action issue="COLLECTIONS-228" dev="scolebourne" type="fix">
+ "MultiValueMap#put(Object, Object)" and "MultiValueMap#putAll(Object, Collection)"
+ now correctly return if the map has changed by this operation.
+ </action>
+ <action issue="COLLECTIONS-226" dev="bayard" type="add" due-to="Vasily Ivanov">
+ Added method "ListOrderedMap#putAll(int, Map)".
+ </action>
+ <action issue="COLLECTIONS-225" dev="tn" type="add" due-to="Sam Berlin, Roger Kapsi">
+ Added new "Trie" interface with a first concrete implementation "PatriciaTrie"
+ together with decorators "Unmodifiable" and "Synchronized".
+ </action>
+ <action issue="COLLECTIONS-223" dev="bayard" type="update" due-to="Vasily Ivanov">
+ "CollectionUtils#addAll(...)" methods now return if the collection has been changed
+ by this operation.
+ </action>
+ <action issue="COLLECTIONS-221" dev="bayard" type="update" due-to="Pal Denes">
+ "CompositeCollection", "CompositeMap" and "CompositeSet" are now serializable.
+ </action>
+ <action issue="COLLECTIONS-219" dev="scolebourne" type="fix" due-to="Tom Leccese">
+ "CollectionUtils#removeAll" wrongly called "ListUtils#retainAll".
+ </action>
+ <action issue="COLLECTIONS-218" dev="skestle" type="update">
+ The "CollectionUtils#select(Collection, Predicate, Collection)" method will now
+ return the output collection.
+ </action>
+ <action issue="COLLECTIONS-217" dev="scolebourne" type="fix" due-to="Matt Bishop">
+ Calling "setValue(Object)" on any Entry returned by a "Flat3Map" will now
+ correctly set the value for the current entry.
+ </action>
+ <action issue="COLLECTIONS-216" dev="scolebourne" type="fix" due-to="Hendrik Maryns">
+ "MultiKey#toString()" will now use "Arrays#toString(List)".
+ </action>
+ <action issue="COLLECTIONS-213" dev="brentworden" type="add" due-to="Dusan Chromy">
+ Added support for resettable iterators in "IteratorIterable".
+ </action>
+ <action issue="COLLECTIONS-194" dev="bayard" type="add" due-to="Dave Meikle">
+ Added methods "MapUtils#populateMap(Map, Iterable, Transformer, ...)".
+ </action>
+ <action issue="COLLECTIONS-182" dev="mbenson" type="update" due-to="Jim Cakalic">
+ "CollectionUtils#forAllDo(Collection, Closure)" now returns the provided closure.
+ </action>
+ <action issue="COLLECTIONS-110,COLLECTIONS-243,COLLECTIONS-245,COLLECTIONS-247,
+ COLLECTIONS-253,COLLECTIONS-273,COLLECTIONS-282" dev="multiple" type="update">
+ Make generic versions of all classes in collections.
+ </action>
+ <action issue="COLLECTIONS-8" dev="brentworden" type="add" due-to="Rune Peter Bjørnstad">
+ Added class "ComparatorPredicate".
+ </action>
+ </release>
+ <release version="3.2.2" date="2015-11-15" description="This is a security and bugfix release.">
+ <action issue="COLLECTIONS-580" dev="tn" type="update">
+ Serialization support for unsafe classes in the functor package is disabled
+ by default as this can be exploited for remote code execution attacks.
+ To re-enable the feature the system property "org.apache.commons.collections.enableUnsafeSerialization"
+ needs to be set to "true".
+ Classes considered to be unsafe are: CloneTransformer, ForClosure, InstantiateFactory,
+ InstantiateTransformer, InvokerTransformer, PrototypeCloneFactory,
+ PrototypeSerializationFactory, WhileClosure.
+ </action>
+ <action issue="COLLECTIONS-538" dev="tn" type="fix" due-to="Trejkaz">
+ "ExtendedProperties" will now use a privileged action to access the
+ "file.separator" system property. In case the class does not have
+ permission to read system properties, the "File#separator" field will
+ be used instead.
+ </action>
+ <action issue="COLLECTIONS-447" dev="tn" type="fix" due-to="Jeffrey Barnes">
+ Tree traversal with a TreeListIterator will not be affected anymore by
+ the removal of an element directly after a call to previous().
+ </action>
+ <action issue="COLLECTIONS-444" dev="tn" type="fix" due-to="Thomas Vahrst, John Vasileff">
+ SetUniqueList.set(int, Object) now works correctly if the object to be inserted
+ is already placed at the given position.
+ </action>
+ <action issue="COLLECTIONS-350" dev="bayard" type="fix" due-to="Michael Akerman">
+ Removed debug output in "MapUtils#getNumber(Map)".
+ </action>
+ <action issue="COLLECTIONS-335" dev="jochen" type="fix" due-to="sebb">
+ Fixed cache assignment for "TreeBidiMap#entrySet".
+ </action>
+ <action issue="COLLECTIONS-334" dev="jochen" type="fix" due-to="sebb">
+ Synchronized access to lock in "StaticBucketMap#size()".
+ </action>
+ <action issue="COLLECTIONS-307" dev="bayard" type="fix" due-to="Christian Semrau">
+ "SetUniqueList#subList()#contains(Object)" will now correctly check the subList
+ rather than the parent list.
+ </action>
+ <action issue="COLLECTIONS-304" dev="bayard" type="fix" due-to="Rafał Figas,Bjorn Townsend">
+ "SetUniqueList#set(int, Object)" will now correctly enforce the uniqueness constraint.
+ </action>
+ <action issue="COLLECTIONS-294" dev="bayard" type="fix" due-to="Benjamin Bentmann">
+ "CaseInsensitiveMap" will now convert input strings to lower-case in a
+ locale-independent manner.
+ </action>
+ <action issue="COLLECTIONS-266" dev="bayard" type="fix" due-to="Joerg Schaible">
+ "MultiKey" will now be correctly serialized/de-serialized.
+ </action>
+ <action issue="COLLECTIONS-261" dev="bayard" type="fix" due-to="ori">
+ "Flat3Map#remove(Object)" will now return the correct value mapped to the removed key
+ if the size of the map is less or equal 3.
+ </action>
+ <action issue="COLLECTIONS-249" dev="bayard" type="fix" due-to="Joe Kelly">
+ "SetUniqueList.addAll(int, Collection)" now correctly add the collection at the
+ provided index.
+ </action>
+ <action issue="COLLECTIONS-228" dev="scolebourne" type="fix">
+ "MultiValueMap#put(Object, Object)" and "MultiValueMap#putAll(Object, Collection)"
+ now correctly return if the map has changed by this operation.
+ </action>
+ <action issue="COLLECTIONS-219" dev="scolebourne" type="fix" due-to="Tom Leccese">
+ "CollectionUtils#removeAll" wrongly called "ListUtils#retainAll".
+ </action>
+ <action issue="COLLECTIONS-217" dev="scolebourne" type="fix" due-to="Matt Bishop">
+ Calling "setValue(Object)" on any Entry returned by a "Flat3Map" will now
+ correctly set the value for the current entry.
+ </action>
+ </release>
+ </body>
+</document>
diff --git a/src/main/java/org/apache/commons/collections4/MapUtils.java b/src/main/java/org/apache/commons/collections4/MapUtils.java
index 08727a0..c5a1516 100644
--- a/src/main/java/org/apache/commons/collections4/MapUtils.java
+++ b/src/main/java/org/apache/commons/collections4/MapUtils.java
@@ -32,6 +32,8 @@ import java.util.Properties;
import java.util.ResourceBundle;
import java.util.SortedMap;
import java.util.TreeMap;
+import java.util.function.BiFunction;
+import java.util.function.Function;
import org.apache.commons.collections4.map.AbstractMapDecorator;
import org.apache.commons.collections4.map.AbstractSortedMapDecorator;
@@ -49,31 +51,29 @@ import org.apache.commons.collections4.map.UnmodifiableMap;
import org.apache.commons.collections4.map.UnmodifiableSortedMap;
/**
- * Provides utility methods and decorators for
- * {@link Map} and {@link SortedMap} instances.
+ * Provides utility methods and decorators for {@link Map} and {@link SortedMap} instances.
* <p>
- * It contains various type safe methods
- * as well as other useful features like deep copying.
+ * It contains various type safe methods as well as other useful features like deep copying.
* </p>
* <p>
* It also provides the following decorators:
* </p>
*
- * <ul>
- * <li>{@link #fixedSizeMap(Map)}
- * <li>{@link #fixedSizeSortedMap(SortedMap)}
- * <li>{@link #lazyMap(Map,Factory)}
- * <li>{@link #lazyMap(Map,Transformer)}
- * <li>{@link #lazySortedMap(SortedMap,Factory)}
- * <li>{@link #lazySortedMap(SortedMap,Transformer)}
- * <li>{@link #predicatedMap(Map,Predicate,Predicate)}
- * <li>{@link #predicatedSortedMap(SortedMap,Predicate,Predicate)}
- * <li>{@link #transformedMap(Map, Transformer, Transformer)}
- * <li>{@link #transformedSortedMap(SortedMap, Transformer, Transformer)}
- * <li>{@link #multiValueMap( Map )}
- * <li>{@link #multiValueMap( Map, Class )}
- * <li>{@link #multiValueMap( Map, Factory )}
- * </ul>
+ * <ul>
+ * <li>{@link #fixedSizeMap(Map)}
+ * <li>{@link #fixedSizeSortedMap(SortedMap)}
+ * <li>{@link #lazyMap(Map,Factory)}
+ * <li>{@link #lazyMap(Map,Transformer)}
+ * <li>{@link #lazySortedMap(SortedMap,Factory)}
+ * <li>{@link #lazySortedMap(SortedMap,Transformer)}
+ * <li>{@link #predicatedMap(Map,Predicate,Predicate)}
+ * <li>{@link #predicatedSortedMap(SortedMap,Predicate,Predicate)}
+ * <li>{@link #transformedMap(Map, Transformer, Transformer)}
+ * <li>{@link #transformedSortedMap(SortedMap, Transformer, Transformer)}
+ * <li>{@link #multiValueMap( Map )}
+ * <li>{@link #multiValueMap( Map, Class )}
+ * <li>{@link #multiValueMap( Map, Factory )}
+ * </ul>
*
* @since 1.0
*/
@@ -81,12 +81,10 @@ import org.apache.commons.collections4.map.UnmodifiableSortedMap;
public class MapUtils {
/**
- * An empty unmodifiable sorted map.
- * This is not provided in the JDK.
+ * An empty unmodifiable sorted map. This is not provided in the JDK.
*/
@SuppressWarnings("rawtypes")
- public static final SortedMap EMPTY_SORTED_MAP =
- UnmodifiableSortedMap.unmodifiableSortedMap(new TreeMap<>());
+ public static final SortedMap EMPTY_SORTED_MAP = UnmodifiableSortedMap.unmodifiableSortedMap(new TreeMap<>());
/**
* String used to indent the verbose and debug Map prints.
@@ -94,61 +92,134 @@ public class MapUtils {
private static final String INDENT_STRING = " ";
/**
- * <code>MapUtils</code> should not normally be instantiated.
+ * Applies the {@code getFunction} and returns its result if non-null, if null returns the result of applying the
+ * default function.
+ *
+ * @param <K> The key type.
+ * @param <R> The result type.
+ * @param map The map to query.
+ * @param key The key into the map.
+ * @param getFunction The get function.
+ * @param defaultFunction The function to provide a default value.
+ * @return The result of applying a function.
*/
- private MapUtils() {}
+ private static <K, R> R applyDefaultFunction(final Map<? super K, ?> map, final K key,
+ final BiFunction<Map<? super K, ?>, K, R> getFunction, final Function<K, R> defaultFunction) {
+ return applyDefaultFunction(map, key, getFunction, defaultFunction, null);
+ }
- // Type safe getters
- //-------------------------------------------------------------------------
/**
- * Gets from a Map in a null-safe manner.
+ * Applies the {@code getFunction} and returns its result if non-null, if null returns the result of applying the
+ * default function.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map, <code>null</code> if null map input
+ * @param <K> The key type.
+ * @param <R> The result type.
+ * @param map The map to query.
+ * @param key The key into the map.
+ * @param getFunction The get function.
+ * @param defaultFunction The function to provide a default value.
+ * @param defaultValue The default value.
+ * @return The result of applying a function.
*/
- public static <K, V> V getObject(final Map<? super K, V> map, final K key) {
- if (map != null) {
- return map.get(key);
+ private static <K, R> R applyDefaultFunction(final Map<? super K, ?> map, final K key,
+ final BiFunction<Map<? super K, ?>, K, R> getFunction, final Function<K, R> defaultFunction,
+ final R defaultValue) {
+ R value = map != null && getFunction != null ? getFunction.apply(map, key) : null;
+ if (value == null) {
+ value = defaultFunction != null ? defaultFunction.apply(key) : null;
}
- return null;
+ return value != null ? value : defaultValue;
}
/**
- * Gets a String from a Map in a null-safe manner.
+ * Applies the {@code getFunction} and returns its result if non-null, if null returns the {@code defaultValue}.
+ *
+ * @param <K> The key type.
+ * @param <R> The result type.
+ * @param map The map to query.
+ * @param key The key into the map.
+ * @param getFunction The get function.
+ * @param defaultValue The default value.
+ * @return The result of applying a function.
+ */
+ private static <K, R> R applyDefaultValue(final Map<? super K, ?> map, final K key,
+ final BiFunction<Map<? super K, ?>, K, R> getFunction, final R defaultValue) {
+ final R value = map != null && getFunction != null ? getFunction.apply(map, key) : null;
+ return value == null ? defaultValue : value;
+ }
+
+ /**
+ * Prints the given map with nice line breaks.
* <p>
- * The String is obtained via <code>toString</code>.
+ * This method prints a nicely formatted String describing the Map. Each map entry will be printed with key, value
+ * and value classname. When the value is a Map, recursive behaviour occurs.
+ * </p>
+ * <p>
+ * This method is NOT thread-safe in any special way. You must manually synchronize on either this class or the
+ * stream as required.
+ * </p>
+ *
+ * @param out the stream to print to, must not be null
+ * @param label The label to be used, may be <code>null</code>. If <code>null</code>, the label is not output. It
+ * typically represents the name of the property in a bean or similar.
+ * @param map The map to print, may be <code>null</code>. If <code>null</code>, the text 'null' is output.
+ * @throws NullPointerException if the stream is <code>null</code>
+ */
+ public static void debugPrint(final PrintStream out, final Object label, final Map<?, ?> map) {
+ verbosePrintInternal(out, label, map, new ArrayDeque<Map<?, ?>>(), true);
+ }
+
+ /**
+ * Returns an immutable empty map if the argument is <code>null</code>, or the argument itself otherwise.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a String, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map, possibly <code>null</code>
+ * @return an empty map if the argument is <code>null</code>
*/
- public static <K> String getString(final Map<? super K, ?> map, final K key) {
- if (map != null) {
- final Object answer = map.get(key);
- if (answer != null) {
- return answer.toString();
- }
- }
- return null;
+ public static <K, V> Map<K, V> emptyIfNull(final Map<K, V> map) {
+ return map == null ? Collections.<K, V>emptyMap() : map;
+ }
+
+ /**
+ * Returns a fixed-sized map backed by the given map. Elements may not be added or removed from the returned map,
+ * but existing elements can be changed (for instance, via the {@link Map#put(Object,Object)} method).
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map whose size to fix, must not be null
+ * @return a fixed-size map backed by that map
+ * @throws NullPointerException if the Map is null
+ */
+ public static <K, V> IterableMap<K, V> fixedSizeMap(final Map<K, V> map) {
+ return FixedSizeMap.fixedSizeMap(map);
+ }
+
+ /**
+ * Returns a fixed-sized sorted map backed by the given sorted map. Elements may not be added or removed from the
+ * returned map, but existing elements can be changed (for instance, via the {@link Map#put(Object,Object)} method).
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map whose size to fix, must not be null
+ * @return a fixed-size map backed by that map
+ * @throws NullPointerException if the SortedMap is null
+ */
+ public static <K, V> SortedMap<K, V> fixedSizeSortedMap(final SortedMap<K, V> map) {
+ return FixedSizeSortedMap.fixedSizeSortedMap(map);
}
/**
* Gets a Boolean from a Map in a null-safe manner.
* <p>
- * If the value is a <code>Boolean</code> it is returned directly.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
+ * If the value is a <code>Boolean</code> it is returned directly. If the value is a <code>String</code> and it
+ * equals 'true' ignoring case then <code>true</code> is returned, otherwise <code>false</code>. If the value is a
+ * <code>Number</code> an integer zero value returns <code>false</code> and non-zero returns <code>true</code>.
* Otherwise, <code>null</code> is returned.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
* @return the value in the Map as a Boolean, <code>null</code> if null map input
*/
public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key) {
@@ -171,47 +242,110 @@ public class MapUtils {
}
/**
- * Gets a Number from a Map in a null-safe manner.
+ * Looks up the given key in the given map, converting the result into a boolean, using the default value if the
+ * conversion fails.
+ *
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a boolean, or defaultValue if the original value is null, the map is null or the
+ * boolean conversion fails
+ */
+ public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key, final Boolean defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getBoolean, defaultValue);
+ }
+
+ /**
+ * Looks up the given key in the given map, converting the result into a boolean, using the defaultFunction to
+ * produce the default value if the conversion fails.
+ *
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a boolean, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the boolean conversion fails
+ * @since 4.5
+ */
+ public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key,
+ final Function<K, Boolean> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getBoolean, defaultFunction);
+ }
+
+ // Type safe primitive getters
+ // -------------------------------------------------------------------------
+ /**
+ * Gets a boolean from a Map in a null-safe manner.
* <p>
- * If the value is a <code>Number</code> it is returned directly.
- * If the value is a <code>String</code> it is converted using
- * {@link NumberFormat#parse(String)} on the system default formatter
- * returning <code>null</code> if the conversion fails.
- * Otherwise, <code>null</code> is returned.
+ * If the value is a <code>Boolean</code> its value is returned. If the value is a <code>String</code> and it equals
+ * 'true' ignoring case then <code>true</code> is returned, otherwise <code>false</code>. If the value is a
+ * <code>Number</code> an integer zero value returns <code>false</code> and non-zero returns <code>true</code>.
+ * Otherwise, <code>false</code> is returned.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Number, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Boolean, <code>false</code> if null map input
*/
- public static <K> Number getNumber(final Map<? super K, ?> map, final K key) {
- if (map != null) {
- final Object answer = map.get(key);
- if (answer != null) {
- if (answer instanceof Number) {
- return (Number) answer;
- }
- if (answer instanceof String) {
- try {
- final String text = (String) answer;
- return NumberFormat.getInstance().parse(text);
- } catch (final ParseException e) { // NOPMD
- // failure means null is returned
- }
- }
- }
- }
- return null;
+ public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key) {
+ return Boolean.TRUE.equals(getBoolean(map, key));
+ }
+
+ // Type safe primitive getters with default values
+ // -------------------------------------------------------------------------
+ /**
+ * Gets a boolean from a Map in a null-safe manner, using the default value if the conversion fails.
+ * <p>
+ * If the value is a <code>Boolean</code> its value is returned. If the value is a <code>String</code> and it equals
+ * 'true' ignoring case then <code>true</code> is returned, otherwise <code>false</code>. If the value is a
+ * <code>Number</code> an integer zero value returns <code>false</code> and non-zero returns <code>true</code>.
+ * Otherwise, <code>defaultValue</code> is returned.
+ * </p>
+ *
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as a Boolean, <code>defaultValue</code> if null map input
+ */
+ public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key, final boolean defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getBoolean, defaultValue).booleanValue();
+ }
+
+ /**
+ * Gets a boolean from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
+ * <p>
+ * If the value is a <code>Boolean</code> its value is returned. If the value is a <code>String</code> and it equals
+ * 'true' ignoring case then <code>true</code> is returned, otherwise <code>false</code>. If the value is a
+ * <code>Number</code> an integer zero value returns <code>false</code> and non-zero returns <code>true</code>.
+ * Otherwise, defaultValue produced by the <code>defaultFunction</code> is returned.
+ * </p>
+ *
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a Boolean, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
+ */
+ public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Boolean> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getBoolean, defaultFunction, false).booleanValue();
}
/**
* Gets a Byte from a Map in a null-safe manner.
* <p>
* The Byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
* @return the value in the Map as a Byte, <code>null</code> if null map input
*/
public static <K> Byte getByte(final Map<? super K, ?> map, final K key) {
@@ -226,97 +360,96 @@ public class MapUtils {
}
/**
- * Gets a Short from a Map in a null-safe manner.
- * <p>
- * The Short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * Looks up the given key in the given map, converting the result into a byte, using the default value if the
+ * conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Short, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static <K> Short getShort(final Map<? super K, ?> map, final K key) {
- final Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- }
- if (answer instanceof Short) {
- return (Short) answer;
- }
- return Short.valueOf(answer.shortValue());
+ public static <K> Byte getByte(final Map<? super K, ?> map, final K key, final Byte defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getByte, defaultValue);
}
/**
- * Gets a Integer from a Map in a null-safe manner.
+ * Looks up the given key in the given map, converting the result into a byte, using the defaultFunction to produce
+ * the default value if the conversion fails.
+ *
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
+ */
+ public static <K> Byte getByte(final Map<? super K, ?> map, final K key, final Function<K, Byte> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getByte, defaultFunction);
+ }
+
+ /**
+ * Gets a byte from a Map in a null-safe manner.
* <p>
- * The Integer is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Integer, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a byte, <code>0</code> if null map input
*/
- public static <K> Integer getInteger(final Map<? super K, ?> map, final K key) {
- final Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- }
- if (answer instanceof Integer) {
- return (Integer) answer;
- }
- return Integer.valueOf(answer.intValue());
+ public static <K> byte getByteValue(final Map<? super K, ?> map, final K key) {
+ return applyDefaultValue(map, key, MapUtils::getByte, 0).byteValue();
}
/**
- * Gets a Long from a Map in a null-safe manner.
+ * Gets a byte from a Map in a null-safe manner, using the default value if the conversion fails.
* <p>
- * The Long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Long, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as a byte, <code>defaultValue</code> if null map input
*/
- public static <K> Long getLong(final Map<? super K, ?> map, final K key) {
- final Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- }
- if (answer instanceof Long) {
- return (Long) answer;
- }
- return Long.valueOf(answer.longValue());
+ public static <K> byte getByteValue(final Map<? super K, ?> map, final K key, final byte defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getByte, defaultValue).byteValue();
}
/**
- * Gets a Float from a Map in a null-safe manner.
+ * Gets a byte from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
* <p>
- * The Float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Float, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a byte, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> Float getFloat(final Map<? super K, ?> map, final K key) {
- final Number answer = getNumber(map, key);
- if (answer == null) {
- return null;
- }
- if (answer instanceof Float) {
- return (Float) answer;
- }
- return Float.valueOf(answer.floatValue());
+ public static <K> byte getByteValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Byte> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getByte, defaultFunction, (byte) 0).byteValue();
}
/**
* Gets a Double from a Map in a null-safe manner.
* <p>
* The Double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
* @return the value in the Map as a Double, <code>null</code> if null map input
*/
public static <K> Double getDouble(final Map<? super K, ?> map, final K key) {
@@ -331,1024 +464,814 @@ public class MapUtils {
}
/**
- * Gets a Map from a Map in a null-safe manner.
- * <p>
- * If the value returned from the specified map is not a Map then
- * <code>null</code> is returned.
+ * Looks up the given key in the given map, converting the result into a double, using the default value if the
+ * conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Map, <code>null</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key) {
- if (map != null) {
- final Object answer = map.get(key);
- if (answer != null && answer instanceof Map) {
- return (Map<?, ?>) answer;
- }
- }
- return null;
+ public static <K> Double getDouble(final Map<? super K, ?> map, final K key, final Double defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getDouble, defaultValue);
}
- // Type safe getters with default values
- //-------------------------------------------------------------------------
/**
- * Looks up the given key in the given map, converting null into the
- * given default value.
+ * Looks up the given key in the given map, converting the result into a double, using the defaultFunction to
+ * produce the default value if the conversion fails.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null
- * @return the value in the map, or defaultValue if the original value
- * is null or the map is null
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
*/
- public static <K, V> V getObject(final Map<K, V> map, final K key, final V defaultValue) {
- if (map != null) {
- final V answer = map.get(key);
- if (answer != null) {
- return answer;
- }
- }
- return defaultValue;
+ public static <K> Double getDouble(final Map<? super K, ?> map, final K key,
+ final Function<K, Double> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getDouble, defaultFunction);
}
/**
- * Looks up the given key in the given map, converting the result into
- * a string, using the default value if the conversion fails.
+ * Gets a double from a Map in a null-safe manner.
+ * <p>
+ * The double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a string, or defaultValue if the
- * original value is null, the map is null or the string conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a double, <code>0.0</code> if null map input
*/
- public static <K> String getString(final Map<? super K, ?> map, final K key, final String defaultValue) {
- String answer = getString(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key) {
+ return applyDefaultValue(map, key, MapUtils::getDouble, 0d).doubleValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a boolean, using the default value if the conversion fails.
+ * Gets a double from a Map in a null-safe manner, using the default value if the conversion fails.
+ * <p>
+ * The double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a boolean, or defaultValue if the
- * original value is null, the map is null or the boolean conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as a double, <code>defaultValue</code> if null map input
*/
- public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key, final Boolean defaultValue) {
- Boolean answer = getBoolean(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key, final double defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getDouble, defaultValue).doubleValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a number, using the default value if the conversion fails.
+ * Gets a double from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
+ * <p>
+ * The double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a double, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> Number getNumber(final Map<? super K, ?> map, final K key, final Number defaultValue) {
- Number answer = getNumber(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Double> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getDouble, defaultFunction, 0d).doubleValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a byte, using the default value if the conversion fails.
+ * Gets a Float from a Map in a null-safe manner.
+ * <p>
+ * The Float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Float, <code>null</code> if null map input
*/
- public static <K> Byte getByte(final Map<? super K, ?> map, final K key, final Byte defaultValue) {
- Byte answer = getByte(map, key);
+ public static <K> Float getFloat(final Map<? super K, ?> map, final K key) {
+ final Number answer = getNumber(map, key);
if (answer == null) {
- answer = defaultValue;
+ return null;
}
- return answer;
+ if (answer instanceof Float) {
+ return (Float) answer;
+ }
+ return Float.valueOf(answer.floatValue());
}
/**
- * Looks up the given key in the given map, converting the result into
- * a short, using the default value if the conversion fails.
+ * Looks up the given key in the given map, converting the result into a float, using the default value if the
+ * conversion fails.
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static <K> Short getShort(final Map<? super K, ?> map, final K key, final Short defaultValue) {
- Short answer = getShort(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> Float getFloat(final Map<? super K, ?> map, final K key, final Float defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getFloat, defaultValue);
}
/**
- * Looks up the given key in the given map, converting the result into
- * an integer, using the default value if the conversion fails.
+ * Looks up the given key in the given map, converting the result into a float, using the defaultFunction to produce
+ * the default value if the conversion fails.
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
*/
- public static <K> Integer getInteger(final Map<? super K, ?> map, final K key, final Integer defaultValue) {
- Integer answer = getInteger(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> Float getFloat(final Map<? super K, ?> map, final K key,
+ final Function<K, Float> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getFloat, defaultFunction);
}
/**
- * Looks up the given key in the given map, converting the result into
- * a long, using the default value if the conversion fails.
+ * Gets a float from a Map in a null-safe manner.
+ * <p>
+ * The float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a float, <code>0.0F</code> if null map input
*/
- public static <K> Long getLong(final Map<? super K, ?> map, final K key, final Long defaultValue) {
- Long answer = getLong(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> float getFloatValue(final Map<? super K, ?> map, final K key) {
+ return applyDefaultValue(map, key, MapUtils::getFloat, 0f).floatValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a float, using the default value if the conversion fails.
+ * Gets a float from a Map in a null-safe manner, using the default value if the conversion fails.
+ * <p>
+ * The float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as a float, <code>defaultValue</code> if null map input
*/
- public static <K> Float getFloat(final Map<? super K, ?> map, final K key, final Float defaultValue) {
- Float answer = getFloat(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> float getFloatValue(final Map<? super K, ?> map, final K key, final float defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getFloat, defaultValue).floatValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a double, using the default value if the conversion fails.
+ * Gets a float from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
+ * <p>
+ * The float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the number conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a float, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> Double getDouble(final Map<? super K, ?> map, final K key, final Double defaultValue) {
- Double answer = getDouble(map, key);
- if (answer == null) {
- answer = defaultValue;
- }
- return answer;
+ public static <K> float getFloatValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Float> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getFloat, defaultFunction, 0f).floatValue();
}
/**
- * Looks up the given key in the given map, converting the result into
- * a map, using the default value if the conversion fails.
+ * Gets a Integer from a Map in a null-safe manner.
+ * <p>
+ * The Integer is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map whose value to look up
- * @param key the key of the value to look up in that map
- * @param defaultValue what to return if the value is null or if the
- * conversion fails
- * @return the value in the map as a number, or defaultValue if the
- * original value is null, the map is null or the map conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Integer, <code>null</code> if null map input
*/
- public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key, final Map<?, ?> defaultValue) {
- Map<?, ?> answer = getMap(map, key);
+ public static <K> Integer getInteger(final Map<? super K, ?> map, final K key) {
+ final Number answer = getNumber(map, key);
if (answer == null) {
- answer = defaultValue;
+ return null;
}
- return answer;
- }
-
- // Type safe primitive getters
- //-------------------------------------------------------------------------
- /**
- * Gets a boolean from a Map in a null-safe manner.
- * <p>
- * If the value is a <code>Boolean</code> its value is returned.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
- * Otherwise, <code>false</code> is returned.
- *
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a Boolean, <code>false</code> if null map input
- */
- public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key) {
- return Boolean.TRUE.equals(getBoolean(map, key));
+ if (answer instanceof Integer) {
+ return (Integer) answer;
+ }
+ return Integer.valueOf(answer.intValue());
}
/**
- * Gets a byte from a Map in a null-safe manner.
- * <p>
- * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * Looks up the given key in the given map, converting the result into an integer, using the defaultFunction to
+ * produce the default value if the conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a byte, <code>0</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
*/
- public static <K> byte getByteValue(final Map<? super K, ?> map, final K key) {
- final Byte byteObject = getByte(map, key);
- if (byteObject == null) {
- return 0;
- }
- return byteObject.byteValue();
+ public static <K> Integer getInteger(final Map<? super K, ?> map, final K key,
+ final Function<K, Integer> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getInteger, defaultFunction);
}
/**
- * Gets a short from a Map in a null-safe manner.
- * <p>
- * The short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * Looks up the given key in the given map, converting the result into an integer, using the default value if the
+ * conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a short, <code>0</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static <K> short getShortValue(final Map<? super K, ?> map, final K key) {
- final Short shortObject = getShort(map, key);
- if (shortObject == null) {
- return 0;
- }
- return shortObject.shortValue();
+ public static <K> Integer getInteger(final Map<? super K, ?> map, final K key, final Integer defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getInteger, defaultValue);
}
/**
* Gets an int from a Map in a null-safe manner.
* <p>
* The int is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
* @return the value in the Map as an int, <code>0</code> if null map input
*/
public static <K> int getIntValue(final Map<? super K, ?> map, final K key) {
- final Integer integerObject = getInteger(map, key);
- if (integerObject == null) {
- return 0;
- }
- return integerObject.intValue();
+ return applyDefaultValue(map, key, MapUtils::getInteger, 0).intValue();
}
/**
- * Gets a long from a Map in a null-safe manner.
+ * Gets an int from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
* <p>
- * The long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The int is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a long, <code>0L</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as an int, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> long getLongValue(final Map<? super K, ?> map, final K key) {
- final Long longObject = getLong(map, key);
- if (longObject == null) {
- return 0L;
- }
- return longObject.longValue();
+ public static <K> int getIntValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Integer> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getInteger, defaultFunction, 0).byteValue();
}
/**
- * Gets a float from a Map in a null-safe manner.
+ * Gets an int from a Map in a null-safe manner, using the default value if the conversion fails.
* <p>
- * The float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The int is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a float, <code>0.0F</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as an int, <code>defaultValue</code> if null map input
*/
- public static <K> float getFloatValue(final Map<? super K, ?> map, final K key) {
- final Float floatObject = getFloat(map, key);
- if (floatObject == null) {
- return 0f;
- }
- return floatObject.floatValue();
+ public static <K> int getIntValue(final Map<? super K, ?> map, final K key, final int defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getInteger, defaultValue).intValue();
}
/**
- * Gets a double from a Map in a null-safe manner.
+ * Gets a Long from a Map in a null-safe manner.
* <p>
- * The double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The Long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @return the value in the Map as a double, <code>0.0</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Long, <code>null</code> if null map input
*/
- public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key) {
- final Double doubleObject = getDouble(map, key);
- if (doubleObject == null) {
- return 0d;
+ public static <K> Long getLong(final Map<? super K, ?> map, final K key) {
+ final Number answer = getNumber(map, key);
+ if (answer == null) {
+ return null;
+ }
+ if (answer instanceof Long) {
+ return (Long) answer;
}
- return doubleObject.doubleValue();
+ return Long.valueOf(answer.longValue());
}
- // Type safe primitive getters with default values
- //-------------------------------------------------------------------------
/**
- * Gets a boolean from a Map in a null-safe manner,
- * using the default value if the conversion fails.
- * <p>
- * If the value is a <code>Boolean</code> its value is returned.
- * If the value is a <code>String</code> and it equals 'true' ignoring case
- * then <code>true</code> is returned, otherwise <code>false</code>.
- * If the value is a <code>Number</code> an integer zero value returns
- * <code>false</code> and non-zero returns <code>true</code>.
- * Otherwise, <code>defaultValue</code> is returned.
+ * Looks up the given key in the given map, converting the result into a Long, using the defaultFunction to produce
+ * the default value if the conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as a Boolean, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
*/
- public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key, final boolean defaultValue) {
- final Boolean booleanObject = getBoolean(map, key);
- if (booleanObject == null) {
- return defaultValue;
- }
- return booleanObject.booleanValue();
+ public static <K> Long getLong(final Map<? super K, ?> map, final K key, final Function<K, Long> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getLong, defaultFunction);
}
/**
- * Gets a byte from a Map in a null-safe manner,
- * using the default value if the conversion fails.
- * <p>
- * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
+ * Looks up the given key in the given map, converting the result into a long, using the default value if the
+ * conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as a byte, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static <K> byte getByteValue(final Map<? super K, ?> map, final K key, final byte defaultValue) {
- final Byte byteObject = getByte(map, key);
- if (byteObject == null) {
- return defaultValue;
- }
- return byteObject.byteValue();
+ public static <K> Long getLong(final Map<? super K, ?> map, final K key, final Long defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getLong, defaultValue);
}
/**
- * Gets a short from a Map in a null-safe manner,
- * using the default value if the conversion fails.
+ * Gets a long from a Map in a null-safe manner.
* <p>
- * The short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as a short, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a long, <code>0L</code> if null map input
*/
- public static <K> short getShortValue(final Map<? super K, ?> map, final K key, final short defaultValue) {
- final Short shortObject = getShort(map, key);
- if (shortObject == null) {
- return defaultValue;
- }
- return shortObject.shortValue();
+ public static <K> long getLongValue(final Map<? super K, ?> map, final K key) {
+ return applyDefaultValue(map, key, MapUtils::getLong, 0L).longValue();
}
/**
- * Gets an int from a Map in a null-safe manner,
- * using the default value if the conversion fails.
+ * Gets a long from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
* <p>
- * The int is obtained from the results of {@link #getNumber(Map,Object)}.
+ * The long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as an int, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a long, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> int getIntValue(final Map<? super K, ?> map, final K key, final int defaultValue) {
- final Integer integerObject = getInteger(map, key);
- if (integerObject == null) {
- return defaultValue;
- }
- return integerObject.intValue();
+ public static <K> long getLongValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Long> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getLong, defaultFunction, 0L).byteValue();
}
/**
- * Gets a long from a Map in a null-safe manner,
- * using the default value if the conversion fails.
+ * Gets a long from a Map in a null-safe manner, using the default value if the conversion fails.
* <p>
* The long is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
* @return the value in the Map as a long, <code>defaultValue</code> if null map input
*/
public static <K> long getLongValue(final Map<? super K, ?> map, final K key, final long defaultValue) {
- final Long longObject = getLong(map, key);
- if (longObject == null) {
- return defaultValue;
- }
- return longObject.longValue();
+ return applyDefaultValue(map, key, MapUtils::getLong, defaultValue).longValue();
}
/**
- * Gets a float from a Map in a null-safe manner,
- * using the default value if the conversion fails.
+ * Gets a Map from a Map in a null-safe manner.
* <p>
- * The float is obtained from the results of {@link #getNumber(Map,Object)}.
+ * If the value returned from the specified map is not a Map then <code>null</code> is returned.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as a float, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Map, <code>null</code> if null map input
*/
- public static <K> float getFloatValue(final Map<? super K, ?> map, final K key, final float defaultValue) {
- final Float floatObject = getFloat(map, key);
- if (floatObject == null) {
- return defaultValue;
+ public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key) {
+ if (map != null) {
+ final Object answer = map.get(key);
+ if (answer != null && answer instanceof Map) {
+ return (Map<?, ?>) answer;
+ }
}
- return floatObject.floatValue();
+ return null;
}
/**
- * Gets a double from a Map in a null-safe manner,
- * using the default value if the conversion fails.
- * <p>
- * The double is obtained from the results of {@link #getNumber(Map,Object)}.
+ * Looks up the given key in the given map, converting the result into a map, using the defaultFunction to produce
+ * the default value if the conversion fails.
*
- * @param <K> the key type
- * @param map the map to use
- * @param key the key to look up
- * @param defaultValue return if the value is null or if the conversion fails
- * @return the value in the Map as a double, <code>defaultValue</code> if null map input
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the map conversion fails
+ * @since 4.5
*/
- public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key, final double defaultValue) {
- final Double doubleObject = getDouble(map, key);
- if (doubleObject == null) {
- return defaultValue;
- }
- return doubleObject.doubleValue();
+ public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key,
+ final Function<K, Map<?, ?>> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getMap, defaultFunction);
+ }
+
+ /**
+ * Looks up the given key in the given map, converting the result into a map, using the default value if the
+ * conversion fails.
+ *
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * map conversion fails
+ */
+ public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key, final Map<?, ?> defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getMap, defaultValue);
}
- // Conversion methods
- //-------------------------------------------------------------------------
/**
- * Gets a new Properties object initialised with the values from a Map.
- * A null input will return an empty properties object.
+ * Gets a Number from a Map in a null-safe manner.
* <p>
- * A Properties object may only store non-null keys and values, thus if
- * the provided map contains either a key or value which is {@code null},
- * a {@link NullPointerException} will be thrown.
+ * If the value is a <code>Number</code> it is returned directly. If the value is a <code>String</code> it is
+ * converted using {@link NumberFormat#parse(String)} on the system default formatter returning <code>null</code> if
+ * the conversion fails. Otherwise, <code>null</code> is returned.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to convert to a Properties object
- * @return the properties object
- * @throws NullPointerException if a key or value in the provided map is {@code null}
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Number, <code>null</code> if null map input
*/
- public static <K, V> Properties toProperties(final Map<K, V> map) {
- final Properties answer = new Properties();
+ public static <K> Number getNumber(final Map<? super K, ?> map, final K key) {
if (map != null) {
- for (final Entry<K, V> entry2 : map.entrySet()) {
- final Map.Entry<?, ?> entry = entry2;
- final Object key = entry.getKey();
- final Object value = entry.getValue();
- answer.put(key, value);
+ final Object answer = map.get(key);
+ if (answer != null) {
+ if (answer instanceof Number) {
+ return (Number) answer;
+ }
+ if (answer instanceof String) {
+ try {
+ final String text = (String) answer;
+ return NumberFormat.getInstance().parse(text);
+ } catch (final ParseException e) { // NOPMD
+ // failure means null is returned
+ }
+ }
}
}
- return answer;
+ return null;
}
/**
- * Creates a new HashMap using data copied from a ResourceBundle.
+ * Looks up the given key in the given map, converting the result into a number, using the defaultFunction to
+ * produce the default value if the conversion fails.
*
- * @param resourceBundle the resource bundle to convert, may not be null
- * @return the hashmap containing the data
- * @throws NullPointerException if the bundle is null
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
*/
- public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
- final Enumeration<String> enumeration = resourceBundle.getKeys();
- final Map<String, Object> map = new HashMap<>();
-
- while (enumeration.hasMoreElements()) {
- final String key = enumeration.nextElement();
- final Object value = resourceBundle.getObject(key);
- map.put(key, value);
- }
-
- return map;
+ public static <K> Number getNumber(final Map<? super K, ?> map, final K key,
+ final Function<K, Number> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getNumber, defaultFunction);
}
- // Printing methods
- //-------------------------------------------------------------------------
/**
- * Prints the given map with nice line breaks.
- * <p>
- * This method prints a nicely formatted String describing the Map.
- * Each map entry will be printed with key and value.
- * When the value is a Map, recursive behaviour occurs.
- * <p>
- * This method is NOT thread-safe in any special way. You must manually
- * synchronize on either this class or the stream as required.
+ * Looks up the given key in the given map, converting the result into a number, using the default value if the
+ * conversion fails.
*
- * @param out the stream to print to, must not be null
- * @param label The label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map The map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output.
- * @throws NullPointerException if the stream is <code>null</code>
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- public static void verbosePrint(final PrintStream out, final Object label, final Map<?, ?> map) {
- verbosePrintInternal(out, label, map, new ArrayDeque<Map<?, ?>>(), false);
+ public static <K> Number getNumber(final Map<? super K, ?> map, final K key, final Number defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getNumber, defaultValue);
}
+ // -------------------------------------------------------------------------
/**
- * Prints the given map with nice line breaks.
- * <p>
- * This method prints a nicely formatted String describing the Map.
- * Each map entry will be printed with key, value and value classname.
- * When the value is a Map, recursive behaviour occurs.
- * <p>
- * This method is NOT thread-safe in any special way. You must manually
- * synchronize on either this class or the stream as required.
+ * Gets from a Map in a null-safe manner.
*
- * @param out the stream to print to, must not be null
- * @param label The label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map The map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output.
- * @throws NullPointerException if the stream is <code>null</code>
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map, <code>null</code> if null map input
*/
- public static void debugPrint(final PrintStream out, final Object label, final Map<?, ?> map) {
- verbosePrintInternal(out, label, map, new ArrayDeque<Map<?, ?>>(), true);
+ public static <K, V> V getObject(final Map<? super K, V> map, final K key) {
+ if (map != null) {
+ return map.get(key);
+ }
+ return null;
}
- // Implementation methods
- //-------------------------------------------------------------------------
- /**
- * Implementation providing functionality for {@link #debugPrint} and for
- * {@link #verbosePrint}. This prints the given map with nice line breaks.
- * If the debug flag is true, it additionally prints the type of the object
- * value. If the contents of a map include the map itself, then the text
- * <em>(this Map)</em> is printed out. If the contents include a
- * parent container of the map, the text <em>(ancestor[i] Map)</em> is
- * printed, where i actually indicates the number of levels which must be
- * traversed in the sequential list of ancestors (e.g. father, grandfather,
- * great-grandfather, etc).
- *
- * @param out the stream to print to
- * @param label the label to be used, may be <code>null</code>.
- * If <code>null</code>, the label is not output.
- * It typically represents the name of the property in a bean or similar.
- * @param map the map to print, may be <code>null</code>.
- * If <code>null</code>, the text 'null' is output
- * @param lineage a stack consisting of any maps in which the previous
- * argument is contained. This is checked to avoid infinite recursion when
- * printing the output
- * @param debug flag indicating whether type names should be output.
- * @throws NullPointerException if the stream is <code>null</code>
+ // -------------------------------------------------------------------------
+ /**
+ * Looks up the given key in the given map, converting null into the given default value.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null
+ * @return the value in the map, or defaultValue if the original value is null or the map is null
*/
- private static void verbosePrintInternal(final PrintStream out, final Object label, final Map<?, ?> map,
- final Deque<Map<?, ?>> lineage, final boolean debug) {
- printIndent(out, lineage.size());
-
- if (map == null) {
- if (label != null) {
- out.print(label);
- out.print(" = ");
+ public static <K, V> V getObject(final Map<K, V> map, final K key, final V defaultValue) {
+ if (map != null) {
+ final V answer = map.get(key);
+ if (answer != null) {
+ return answer;
}
- out.println("null");
- return;
- }
- if (label != null) {
- out.print(label);
- out.println(" = ");
}
+ return defaultValue;
+ }
- printIndent(out, lineage.size());
- out.println("{");
-
- lineage.addLast(map);
-
- for (final Map.Entry<?, ?> entry : map.entrySet()) {
- final Object childKey = entry.getKey();
- final Object childValue = entry.getValue();
- if (childValue instanceof Map && !lineage.contains(childValue)) {
- verbosePrintInternal(
- out,
- childKey == null ? "null" : childKey,
- (Map<?, ?>) childValue,
- lineage,
- debug);
- } else {
- printIndent(out, lineage.size());
- out.print(childKey);
- out.print(" = ");
-
- final int lineageIndex =
- IterableUtils.indexOf(lineage,
- PredicateUtils.equalPredicate(childValue));
- if (lineageIndex == -1) {
- out.print(childValue);
- } else if (lineage.size() - 1 == lineageIndex) {
- out.print("(this Map)");
- } else {
- out.print(
- "(ancestor["
- + (lineage.size() - 1 - lineageIndex - 1)
- + "] Map)");
- }
-
- if (debug && childValue != null) {
- out.print(' ');
- out.println(childValue.getClass().getName());
- } else {
- out.println();
- }
- }
+ /**
+ * Gets a Short from a Map in a null-safe manner.
+ * <p>
+ * The Short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
+ *
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a Short, <code>null</code> if null map input
+ */
+ public static <K> Short getShort(final Map<? super K, ?> map, final K key) {
+ final Number answer = getNumber(map, key);
+ if (answer == null) {
+ return null;
}
+ if (answer instanceof Short) {
+ return (Short) answer;
+ }
+ return Short.valueOf(answer.shortValue());
+ }
- lineage.removeLast();
-
- printIndent(out, lineage.size());
- out.println(debug ? "} " + map.getClass().getName() : "}");
+ /**
+ * Looks up the given key in the given map, converting the result into a short, using the defaultFunction to produce
+ * the default value if the conversion fails.
+ *
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the number conversion fails
+ * @since 4.5
+ */
+ public static <K> Short getShort(final Map<? super K, ?> map, final K key,
+ final Function<K, Short> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getShort, defaultFunction);
}
/**
- * Writes indentation to the given stream.
+ * Looks up the given key in the given map, converting the result into a short, using the default value if the
+ * conversion fails.
*
- * @param out the stream to indent
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a number, or defaultValue if the original value is null, the map is null or the
+ * number conversion fails
*/
- private static void printIndent(final PrintStream out, final int indent) {
- for (int i = 0; i < indent; i++) {
- out.print(INDENT_STRING);
- }
+ public static <K> Short getShort(final Map<? super K, ?> map, final K key, final Short defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getShort, defaultValue);
}
- // Misc
- //-----------------------------------------------------------------------
/**
- * Inverts the supplied map returning a new HashMap such that the keys of
- * the input are swapped with the values.
+ * Gets a short from a Map in a null-safe manner.
* <p>
- * This operation assumes that the inverse mapping is well defined.
- * If the input map had multiple entries with the same value mapped to
- * different keys, the returned map will map one of those keys to the
- * value, but the exact key which will be mapped is undefined.
+ * The short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to invert, may not be null
- * @return a new HashMap containing the inverted data
- * @throws NullPointerException if the map is null
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a short, <code>0</code> if null map input
*/
- public static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
- final Map<V, K> out = new HashMap<>(map.size());
- for (final Entry<K, V> entry : map.entrySet()) {
- out.put(entry.getValue(), entry.getKey());
- }
- return out;
+ public static <K> short getShortValue(final Map<? super K, ?> map, final K key) {
+ return applyDefaultValue(map, key, MapUtils::getShort, 0).shortValue();
}
- //-----------------------------------------------------------------------
/**
- * Protects against adding null values to a map.
- * <p>
- * This method checks the value being added to the map, and if it is null
- * it is replaced by an empty string.
- * <p>
- * This could be useful if the map does not accept null values, or for
- * receiving data from a source that may provide null or empty string
- * which should be held in the same way in the map.
+ * Gets a short from a Map in a null-safe manner, using the default value produced by the defaultFunction if the
+ * conversion fails.
* <p>
- * Keys are not validated.
- * Note that this method can be used to circumvent the map's
- * value type at runtime.
+ * The short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param map the map to add to, may not be null
- * @param key the key
- * @param value the value, null converted to ""
- * @throws NullPointerException if the map is null
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultFunction produce the default value to return if the value is null or if the conversion fails
+ * @return the value in the Map as a short, default value produced by the <code>defaultFunction</code> if null map
+ * input
+ * @since 4.5
*/
- public static <K> void safeAddToMap(final Map<? super K, Object> map, final K key, final Object value)
- throws NullPointerException {
- map.put(key, value == null ? "" : value);
+ public static <K> short getShortValue(final Map<? super K, ?> map, final K key,
+ final Function<K, Short> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getShort, defaultFunction, (short) 0).shortValue();
}
- //-----------------------------------------------------------------------
/**
- * Puts all the keys and values from the specified array into the map.
- * <p>
- * This method is an alternative to the {@link java.util.Map#putAll(java.util.Map)}
- * method and constructors. It allows you to build a map from an object array
- * of various possible styles.
+ * Gets a short from a Map in a null-safe manner, using the default value if the conversion fails.
* <p>
- * If the first entry in the object array implements {@link java.util.Map.Entry}
- * or {@link KeyValue} then the key and value are added from that object.
- * If the first entry in the object array is an object array itself, then
- * it is assumed that index 0 in the sub-array is the key and index 1 is the value.
- * Otherwise, the array is treated as keys and values in alternate indices.
- * <p>
- * For example, to create a color map:
- * <pre>
- * Map colorMap = MapUtils.putAll(new HashMap(), new String[][] {
- * {"RED", "#FF0000"},
- * {"GREEN", "#00FF00"},
- * {"BLUE", "#0000FF"}
- * });
- * </pre>
- * or:
- * <pre>
- * Map colorMap = MapUtils.putAll(new HashMap(), new String[] {
- * "RED", "#FF0000",
- * "GREEN", "#00FF00",
- * "BLUE", "#0000FF"
- * });
- * </pre>
- * or:
- * <pre>
- * Map colorMap = MapUtils.putAll(new HashMap(), new Map.Entry[] {
- * new DefaultMapEntry("RED", "#FF0000"),
- * new DefaultMapEntry("GREEN", "#00FF00"),
- * new DefaultMapEntry("BLUE", "#0000FF")
- * });
- * </pre>
+ * The short is obtained from the results of {@link #getNumber(Map,Object)}.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to populate, must not be null
- * @param array an array to populate from, null ignored
- * @return the input map
- * @throws NullPointerException if map is null
- * @throws IllegalArgumentException if sub-array or entry matching used and an entry is invalid
- * @throws ClassCastException if the array contents is mixed
- * @since 3.2
+ * @param <K> the key type
+ * @param map the map to use
+ * @param key the key to look up
+ * @param defaultValue return if the value is null or if the conversion fails
+ * @return the value in the Map as a short, <code>defaultValue</code> if null map input
*/
- @SuppressWarnings("unchecked") // As per Javadoc throws CCE for invalid array contents
- public static <K, V> Map<K, V> putAll(final Map<K, V> map, final Object[] array) {
- if (map == null) {
- throw new NullPointerException("The map must not be null");
- }
- if (array == null || array.length == 0) {
- return map;
- }
- final Object obj = array[0];
- if (obj instanceof Map.Entry) {
- for (final Object element : array) {
- // cast ok here, type is checked above
- final Map.Entry<K, V> entry = (Map.Entry<K, V>) element;
- map.put(entry.getKey(), entry.getValue());
- }
- } else if (obj instanceof KeyValue) {
- for (final Object element : array) {
- // cast ok here, type is checked above
- final KeyValue<K, V> keyval = (KeyValue<K, V>) element;
- map.put(keyval.getKey(), keyval.getValue());
- }
- } else if (obj instanceof Object[]) {
- for (int i = 0; i < array.length; i++) {
- final Object[] sub = (Object[]) array[i];
- if (sub == null || sub.length < 2) {
- throw new IllegalArgumentException("Invalid array element: " + i);
- }
- // these casts can fail if array has incorrect types
- map.put((K) sub[0], (V) sub[1]);
- }
- } else {
- for (int i = 0; i < array.length - 1;) {
- // these casts can fail if array has incorrect types
- map.put((K) array[i++], (V) array[i++]);
- }
- }
- return map;
+ public static <K> short getShortValue(final Map<? super K, ?> map, final K key, final short defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getShort, defaultValue).shortValue();
}
- //-----------------------------------------------------------------------
-
/**
- * Returns an immutable empty map if the argument is <code>null</code>,
- * or the argument itself otherwise.
+ * Gets a String from a Map in a null-safe manner.
+ * <p>
+ * The String is obtained via <code>toString</code>.
+ * </p>
*
* @param <K> the key type
- * @param <V> the value type
- * @param map the map, possibly <code>null</code>
- * @return an empty map if the argument is <code>null</code>
+ * @param map the map to use
+ * @param key the key to look up
+ * @return the value in the Map as a String, <code>null</code> if null map input
*/
- public static <K,V> Map<K,V> emptyIfNull(final Map<K,V> map) {
- return map == null ? Collections.<K,V>emptyMap() : map;
+ public static <K> String getString(final Map<? super K, ?> map, final K key) {
+ if (map != null) {
+ final Object answer = map.get(key);
+ if (answer != null) {
+ return answer.toString();
+ }
+ }
+ return null;
}
/**
- * Null-safe check if the specified map is empty.
- * <p>
- * Null returns true.
+ * Looks up the given key in the given map, converting the result into a string, using the defaultFunction to
+ * produce the default value if the conversion fails.
*
- * @param map the map to check, may be null
- * @return true if empty or null
- * @since 3.2
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultFunction what to produce the default value if the value is null or if the conversion fails
+ * @return the value in the map as a string, or defaultValue produced by the defaultFunction if the original value
+ * is null, the map is null or the string conversion fails
+ * @since 4.5
*/
- public static boolean isEmpty(final Map<?,?> map) {
- return map == null || map.isEmpty();
+ public static <K> String getString(final Map<? super K, ?> map, final K key,
+ final Function<K, String> defaultFunction) {
+ return applyDefaultFunction(map, key, MapUtils::getString, defaultFunction);
}
/**
- * Null-safe check if the specified map is not empty.
- * <p>
- * Null returns false.
+ * Looks up the given key in the given map, converting the result into a string, using the default value if the
+ * conversion fails.
*
- * @param map the map to check, may be null
- * @return true if non-null and non-empty
- * @since 3.2
+ * @param <K> the key type
+ * @param map the map whose value to look up
+ * @param key the key of the value to look up in that map
+ * @param defaultValue what to return if the value is null or if the conversion fails
+ * @return the value in the map as a string, or defaultValue if the original value is null, the map is null or the
+ * string conversion fails
*/
- public static boolean isNotEmpty(final Map<?,?> map) {
- return !MapUtils.isEmpty(map);
+ public static <K> String getString(final Map<? super K, ?> map, final K key, final String defaultValue) {
+ return applyDefaultValue(map, key, MapUtils::getString, defaultValue);
}
- // Map decorators
- //-----------------------------------------------------------------------
+ // Misc
+ // -----------------------------------------------------------------------
/**
- * Returns a synchronized map backed by the given map.
+ * Inverts the supplied map returning a new HashMap such that the keys of the input are swapped with the values.
* <p>
- * You must manually synchronize on the returned buffer's iterator to
- * avoid non-deterministic behavior:
- *
- * <pre>
- * Map m = MapUtils.synchronizedMap(myMap);
- * Set s = m.keySet(); // outside synchronized block
- * synchronized (m) { // synchronized on MAP!
- * Iterator i = s.iterator();
- * while (i.hasNext()) {
- * process (i.next());
- * }
- * }
- * </pre>
- *
- * This method uses the implementation in {@link java.util.Collections Collections}.
+ * This operation assumes that the inverse mapping is well defined. If the input map had multiple entries with the
+ * same value mapped to different keys, the returned map will map one of those keys to the value, but the exact key
+ * which will be mapped is undefined.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to synchronize, must not be null
- * @return a synchronized map backed by the given map
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to invert, may not be null
+ * @return a new HashMap containing the inverted data
+ * @throws NullPointerException if the map is null
*/
- public static <K, V> Map<K, V> synchronizedMap(final Map<K, V> map) {
- return Collections.synchronizedMap(map);
+ public static <K, V> Map<V, K> invertMap(final Map<K, V> map) {
+ final Map<V, K> out = new HashMap<>(map.size());
+ for (final Entry<K, V> entry : map.entrySet()) {
+ out.put(entry.getValue(), entry.getKey());
+ }
+ return out;
}
/**
- * Returns an unmodifiable map backed by the given map.
+ * Null-safe check if the specified map is empty.
* <p>
- * This method uses the implementation in the decorators subpackage.
+ * Null returns true.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to make unmodifiable, must not be null
- * @return an unmodifiable map backed by the given map
- * @throws NullPointerException if the map is null
+ * @param map the map to check, may be null
+ * @return true if empty or null
+ * @since 3.2
*/
- public static <K, V> Map<K, V> unmodifiableMap(final Map<? extends K, ? extends V> map) {
- return UnmodifiableMap.unmodifiableMap(map);
+ public static boolean isEmpty(final Map<?, ?> map) {
+ return map == null || map.isEmpty();
}
/**
- * Returns a predicated (validating) map backed by the given map.
+ * Null-safe check if the specified map is not empty.
* <p>
- * Only objects that pass the tests in the given predicates can be added to the map.
- * Trying to add an invalid object results in an IllegalArgumentException.
- * Keys must pass the key predicate, values must pass the value predicate.
- * It is important not to use the original map after invoking this method,
- * as it is a backdoor for adding invalid objects.
- *
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to predicate, must not be null
- * @param keyPred the predicate for keys, null means no check
- * @param valuePred the predicate for values, null means no check
- * @return a predicated map backed by the given map
- * @throws NullPointerException if the Map is null
+ * Null returns false.
+ * </p>
+ *
+ * @param map the map to check, may be null
+ * @return true if non-null and non-empty
+ * @since 3.2
*/
- public static <K, V> IterableMap<K, V> predicatedMap(final Map<K, V> map, final Predicate<? super K> keyPred,
- final Predicate<? super V> valuePred) {
- return PredicatedMap.predicatedMap(map, keyPred, valuePred);
+ public static boolean isNotEmpty(final Map<?, ?> map) {
+ return !MapUtils.isEmpty(map);
}
/**
- * Returns a transformed map backed by the given map.
- * <p>
- * This method returns a new map (decorating the specified map) that
- * will transform any new entries added to it.
- * Existing entries in the specified map will not be transformed.
- * If you want that behaviour, see {@link TransformedMap#transformedMap}.
- * <p>
- * Each object is passed through the transformers as it is added to the
- * Map. It is important not to use the original map after invoking this
- * method, as it is a backdoor for adding untransformed objects.
- * <p>
- * If there are any elements already in the map being decorated, they
- * are NOT transformed.
+ * Get the specified {@link Map} as an {@link IterableMap}.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to transform, must not be null, typically empty
- * @param keyTransformer the transformer for the map keys, null means no transformation
- * @param valueTransformer the transformer for the map values, null means no transformation
- * @return a transformed map backed by the given map
- * @throws NullPointerException if the Map is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map to wrap if necessary.
+ * @return IterableMap<K, V>
+ * @throws NullPointerException if map is null
+ * @since 4.0
*/
- public static <K, V> IterableMap<K, V> transformedMap(final Map<K, V> map,
- final Transformer<? super K, ? extends K> keyTransformer,
- final Transformer<? super V, ? extends V> valueTransformer) {
- return TransformedMap.transformingMap(map, keyTransformer, valueTransformer);
+ public static <K, V> IterableMap<K, V> iterableMap(final Map<K, V> map) {
+ if (map == null) {
+ throw new NullPointerException("Map must not be null");
+ }
+ return map instanceof IterableMap ? (IterableMap<K, V>) map : new AbstractMapDecorator<K, V>(map) {
+ };
}
/**
- * Returns a fixed-sized map backed by the given map.
- * Elements may not be added or removed from the returned map, but
- * existing elements can be changed (for instance, via the
- * {@link Map#put(Object,Object)} method).
+ * Get the specified {@link SortedMap} as an {@link IterableSortedMap}.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map whose size to fix, must not be null
- * @return a fixed-size map backed by that map
- * @throws NullPointerException if the Map is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param sortedMap to wrap if necessary
+ * @return {@link IterableSortedMap}<K, V>
+ * @throws NullPointerException if sortedMap is null
+ * @since 4.0
*/
- public static <K, V> IterableMap<K, V> fixedSizeMap(final Map<K, V> map) {
- return FixedSizeMap.fixedSizeMap(map);
+ public static <K, V> IterableSortedMap<K, V> iterableSortedMap(final SortedMap<K, V> sortedMap) {
+ if (sortedMap == null) {
+ throw new NullPointerException("Map must not be null");
+ }
+ return sortedMap instanceof IterableSortedMap ? (IterableSortedMap<K, V>) sortedMap
+ : new AbstractSortedMapDecorator<K, V>(sortedMap) {
+ };
}
/**
* Returns a "lazy" map whose values will be created on demand.
* <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key.
+ * When the key passed to the returned map's {@link Map#get(Object)} method is not present in the map, then the
+ * factory will be used to create a new object and that object will become the value associated with that key.
+ * </p>
* <p>
* For instance:
+ * </p>
* <pre>
* Factory factory = new Factory() {
* public Object create() {
@@ -1359,31 +1282,34 @@ public class MapUtils {
* Object obj = lazyMap.get("test");
* </pre>
*
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
- * instance is the value for the <code>"test"</code> key in the map.
+ * <p>
+ * After the above code is executed, <code>obj</code> will contain a new <code>Date</code> instance. Furthermore,
+ * that <code>Date</code> instance is the value for the <code>"test"</code> key in the map.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to make lazy, must not be null
- * @param factory the factory for creating new objects, must not be null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to make lazy, must not be null
+ * @param factory the factory for creating new objects, must not be null
* @return a lazy map backed by the given map
- * @throws NullPointerException if the Map or Factory is null
+ * @throws NullPointerException if the Map or Factory is null
*/
public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map, final Factory<? extends V> factory) {
return LazyMap.lazyMap(map, factory);
}
+ // -----------------------------------------------------------------------
+
/**
* Returns a "lazy" map whose values will be created on demand.
* <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key. The factory is a {@link Transformer}
- * that will be passed the key which it must transform into the value.
+ * When the key passed to the returned map's {@link Map#get(Object)} method is not present in the map, then the
+ * factory will be used to create a new object and that object will become the value associated with that key. The
+ * factory is a {@link Transformer} that will be passed the key which it must transform into the value.
+ * </p>
* <p>
* For instance:
+ * </p>
* <pre>
* Transformer factory = new Transformer() {
* public Object transform(Object mapKey) {
@@ -1394,22 +1320,23 @@ public class MapUtils {
* Object obj = lazyMap.get("C:/dev");
* </pre>
*
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>File</code> instance for the C drive dev directory.
- * Furthermore, that <code>File</code> instance is the value for the
- * <code>"C:/dev"</code> key in the map.
* <p>
- * If a lazy map is wrapped by a synchronized map, the result is a simple
- * synchronized cache. When an object is not is the cache, the cache itself
- * calls back to the factory Transformer to populate itself, all within the
- * same synchronized block.
+ * After the above code is executed, <code>obj</code> will contain a new <code>File</code> instance for the C drive
+ * dev directory. Furthermore, that <code>File</code> instance is the value for the <code>"C:/dev"</code> key in the
+ * map.
+ * </p>
+ * <p>
+ * If a lazy map is wrapped by a synchronized map, the result is a simple synchronized cache. When an object is not
+ * is the cache, the cache itself calls back to the factory Transformer to populate itself, all within the same
+ * synchronized block.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to make lazy, must not be null
- * @param transformerFactory the factory for creating new objects, must not be null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to make lazy, must not be null
+ * @param transformerFactory the factory for creating new objects, must not be null
* @return a lazy map backed by the given map
- * @throws NullPointerException if the Map or Transformer is null
+ * @throws NullPointerException if the Map or Transformer is null
*/
public static <K, V> IterableMap<K, V> lazyMap(final Map<K, V> map,
final Transformer<? super K, ? extends V> transformerFactory) {
@@ -1417,29 +1344,87 @@ public class MapUtils {
}
/**
- * Returns a map that maintains the order of keys that are added
- * backed by the given map.
+ * Returns a "lazy" sorted map whose values will be created on demand.
* <p>
- * If a key is added twice, the order is determined by the first add.
- * The order is observed through the keySet, values and entrySet.
+ * When the key passed to the returned map's {@link Map#get(Object)} method is not present in the map, then the
+ * factory will be used to create a new object and that object will become the value associated with that key.
+ * </p>
+ * <p>
+ * For instance:
+ * </p>
+ * <pre>
+ * Factory factory = new Factory() {
+ * public Object create() {
+ * return new Date();
+ * }
+ * }
+ * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
+ * Object obj = lazy.get("test");
+ * </pre>
+ * <p>
+ * After the above code is executed, <code>obj</code> will contain a new <code>Date</code> instance. Furthermore,
+ * that <code>Date</code> instance is the value for the <code>"test"</code> key.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to order, must not be null
- * @return an ordered map backed by the given map
- * @throws NullPointerException if the Map is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to make lazy, must not be null
+ * @param factory the factory for creating new objects, must not be null
+ * @return a lazy map backed by the given map
+ * @throws NullPointerException if the SortedMap or Factory is null
*/
- public static <K, V> OrderedMap<K, V> orderedMap(final Map<K, V> map) {
- return ListOrderedMap.listOrderedMap(map);
+ public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map, final Factory<? extends V> factory) {
+ return LazySortedMap.lazySortedMap(map, factory);
+ }
+
+ /**
+ * Returns a "lazy" sorted map whose values will be created on demand.
+ * <p>
+ * When the key passed to the returned map's {@link Map#get(Object)} method is not present in the map, then the
+ * factory will be used to create a new object and that object will become the value associated with that key. The
+ * factory is a {@link Transformer} that will be passed the key which it must transform into the value.
+ * </p>
+ * <p>
+ * For instance:
+ * </p>
+ * <pre>
+ * Transformer factory = new Transformer() {
+ * public Object transform(Object mapKey) {
+ * return new File(mapKey);
+ * }
+ * }
+ * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
+ * Object obj = lazy.get("C:/dev");
+ * </pre>
+ * <p>
+ * After the above code is executed, <code>obj</code> will contain a new <code>File</code> instance for the C drive
+ * dev directory. Furthermore, that <code>File</code> instance is the value for the <code>"C:/dev"</code> key in the
+ * map.
+ * </p>
+ * <p>
+ * If a lazy map is wrapped by a synchronized map, the result is a simple synchronized cache. When an object is not
+ * is the cache, the cache itself calls back to the factory Transformer to populate itself, all within the same
+ * synchronized block.
+ * </p>
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to make lazy, must not be null
+ * @param transformerFactory the factory for creating new objects, must not be null
+ * @return a lazy map backed by the given map
+ * @throws NullPointerException if the Map or Transformer is null
+ */
+ public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map,
+ final Transformer<? super K, ? extends V> transformerFactory) {
+ return LazySortedMap.lazySortedMap(map, transformerFactory);
}
/**
- * Creates a mult-value map backed by the given map which returns
- * collections of type ArrayList.
+ * Creates a mult-value map backed by the given map which returns collections of type ArrayList.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to decorate
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to decorate
* @return a multi-value map backed by the given map which returns ArrayLists of values.
* @see MultiValueMap
* @since 3.2
@@ -1451,15 +1436,14 @@ public class MapUtils {
}
/**
- * Creates a multi-value map backed by the given map which returns
- * collections of the specified type.
+ * Creates a multi-value map backed by the given map which returns collections of the specified type.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param <C> the collection class type
- * @param map the map to decorate
- * @param collectionClass the type of collections to return from the map
- * (must contain public no-arg constructor and extend Collection)
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param <C> the collection class type
+ * @param map the map to decorate
+ * @param collectionClass the type of collections to return from the map (must contain public no-arg constructor and
+ * extend Collection)
* @return a multi-value map backed by the given map which returns collections of the specified type
* @see MultiValueMap
* @since 3.2
@@ -1472,16 +1456,16 @@ public class MapUtils {
}
/**
- * Creates a multi-value map backed by the given map which returns
- * collections created by the specified collection factory.
+ * Creates a multi-value map backed by the given map which returns collections created by the specified collection
+ * factory.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param <C> the collection class type
- * @param map the map to decorate
- * @param collectionFactory a factor which creates collection objects
- * @return a multi-value map backed by the given map which returns collections
- * created by the specified collection factory
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param <C> the collection class type
+ * @param map the map to decorate
+ * @param collectionFactory a factor which creates collection objects
+ * @return a multi-value map backed by the given map which returns collections created by the specified collection
+ * factory
* @see MultiValueMap
* @since 3.2
* @deprecated since 4.1, use {@link MultiValuedMap} instead
@@ -1492,68 +1476,135 @@ public class MapUtils {
return MultiValueMap.multiValueMap(map, collectionFactory);
}
- // SortedMap decorators
- //-----------------------------------------------------------------------
/**
- * Returns a synchronized sorted map backed by the given sorted map.
+ * Returns a map that maintains the order of keys that are added backed by the given map.
* <p>
- * You must manually synchronize on the returned buffer's iterator to
- * avoid non-deterministic behavior:
+ * If a key is added twice, the order is determined by the first add. The order is observed through the keySet,
+ * values and entrySet.
+ * </p>
*
- * <pre>
- * Map m = MapUtils.synchronizedSortedMap(myMap);
- * Set s = m.keySet(); // outside synchronized block
- * synchronized (m) { // synchronized on MAP!
- * Iterator i = s.iterator();
- * while (i.hasNext()) {
- * process (i.next());
- * }
- * }
- * </pre>
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to order, must not be null
+ * @return an ordered map backed by the given map
+ * @throws NullPointerException if the Map is null
+ */
+ public static <K, V> OrderedMap<K, V> orderedMap(final Map<K, V> map) {
+ return ListOrderedMap.listOrderedMap(map);
+ }
+
+ /**
+ * Populates a Map using the supplied <code>Transformer</code>s to transform the elements into keys and values.
*
- * This method uses the implementation in {@link java.util.Collections Collections}.
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param <E> the type of object contained in the {@link Iterable}
+ * @param map the <code>Map</code> to populate.
+ * @param elements the <code>Iterable</code> containing the input values for the map.
+ * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
+ * @param valueTransformer the <code>Transformer</code> used to transform the element into a value
+ * @throws NullPointerException if the map, elements or transformers are null
+ */
+ public static <K, V, E> void populateMap(final Map<K, V> map, final Iterable<? extends E> elements,
+ final Transformer<E, K> keyTransformer, final Transformer<E, V> valueTransformer) {
+ final Iterator<? extends E> iter = elements.iterator();
+ while (iter.hasNext()) {
+ final E temp = iter.next();
+ map.put(keyTransformer.transform(temp), valueTransformer.transform(temp));
+ }
+ }
+
+ /**
+ * Populates a Map using the supplied <code>Transformer</code> to transform the elements into keys, using the
+ * unaltered element as the value in the <code>Map</code>.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to synchronize, must not be null
- * @return a synchronized map backed by the given map
- * @throws NullPointerException if the map is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the <code>Map</code> to populate.
+ * @param elements the <code>Iterable</code> containing the input values for the map.
+ * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
+ * @throws NullPointerException if the map, elements or transformer are null
*/
- public static <K, V> SortedMap<K, V> synchronizedSortedMap(final SortedMap<K, V> map) {
- return Collections.synchronizedSortedMap(map);
+ public static <K, V> void populateMap(final Map<K, V> map, final Iterable<? extends V> elements,
+ final Transformer<V, K> keyTransformer) {
+ populateMap(map, elements, keyTransformer, TransformerUtils.<V>nopTransformer());
}
/**
- * Returns an unmodifiable sorted map backed by the given sorted map.
+ * Populates a MultiMap using the supplied <code>Transformer</code>s to transform the elements into keys and values.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param <E> the type of object contained in the {@link Iterable}
+ * @param map the <code>MultiMap</code> to populate.
+ * @param elements the <code>Iterable</code> containing the input values for the map.
+ * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
+ * @param valueTransformer the <code>Transformer</code> used to transform the element into a value
+ * @throws NullPointerException if the map, collection or transformers are null
+ */
+ public static <K, V, E> void populateMap(final MultiMap<K, V> map, final Iterable<? extends E> elements,
+ final Transformer<E, K> keyTransformer, final Transformer<E, V> valueTransformer) {
+ final Iterator<? extends E> iter = elements.iterator();
+ while (iter.hasNext()) {
+ final E temp = iter.next();
+ map.put(keyTransformer.transform(temp), valueTransformer.transform(temp));
+ }
+ }
+
+ /**
+ * Populates a MultiMap using the supplied <code>Transformer</code> to transform the elements into keys, using the
+ * unaltered element as the value in the <code>MultiMap</code>.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the <code>MultiMap</code> to populate.
+ * @param elements the <code>Iterable</code> to use as input values for the map.
+ * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
+ * @throws NullPointerException if the map, elements or transformer are null
+ */
+ public static <K, V> void populateMap(final MultiMap<K, V> map, final Iterable<? extends V> elements,
+ final Transformer<V, K> keyTransformer) {
+ populateMap(map, elements, keyTransformer, TransformerUtils.<V>nopTransformer());
+ }
+
+ /**
+ * Returns a predicated (validating) map backed by the given map.
* <p>
- * This method uses the implementation in the decorators subpackage.
+ * Only objects that pass the tests in the given predicates can be added to the map. Trying to add an invalid object
+ * results in an IllegalArgumentException. Keys must pass the key predicate, values must pass the value predicate.
+ * It is important not to use the original map after invoking this method, as it is a backdoor for adding invalid
+ * objects.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the sorted map to make unmodifiable, must not be null
- * @return an unmodifiable map backed by the given map
- * @throws NullPointerException if the map is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to predicate, must not be null
+ * @param keyPred the predicate for keys, null means no check
+ * @param valuePred the predicate for values, null means no check
+ * @return a predicated map backed by the given map
+ * @throws NullPointerException if the Map is null
*/
- public static <K, V> SortedMap<K, V> unmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
- return UnmodifiableSortedMap.unmodifiableSortedMap(map);
+ public static <K, V> IterableMap<K, V> predicatedMap(final Map<K, V> map, final Predicate<? super K> keyPred,
+ final Predicate<? super V> valuePred) {
+ return PredicatedMap.predicatedMap(map, keyPred, valuePred);
}
/**
* Returns a predicated (validating) sorted map backed by the given map.
* <p>
- * Only objects that pass the tests in the given predicates can be added to the map.
- * Trying to add an invalid object results in an IllegalArgumentException.
- * Keys must pass the key predicate, values must pass the value predicate.
- * It is important not to use the original map after invoking this method,
- * as it is a backdoor for adding invalid objects.
- *
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to predicate, must not be null
- * @param keyPred the predicate for keys, null means no check
- * @param valuePred the predicate for values, null means no check
+ * Only objects that pass the tests in the given predicates can be added to the map. Trying to add an invalid object
+ * results in an IllegalArgumentException. Keys must pass the key predicate, values must pass the value predicate.
+ * It is important not to use the original map after invoking this method, as it is a backdoor for adding invalid
+ * objects.
+ * </p>
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to predicate, must not be null
+ * @param keyPred the predicate for keys, null means no check
+ * @param valuePred the predicate for values, null means no check
* @return a predicated map backed by the given map
- * @throws NullPointerException if the SortedMap is null
+ * @throws NullPointerException if the SortedMap is null
*/
public static <K, V> SortedMap<K, V> predicatedSortedMap(final SortedMap<K, V> map,
final Predicate<? super K> keyPred, final Predicate<? super V> valuePred) {
@@ -1561,247 +1612,440 @@ public class MapUtils {
}
/**
- * Returns a transformed sorted map backed by the given map.
+ * Writes indentation to the given stream.
+ *
+ * @param out the stream to indent
+ */
+ private static void printIndent(final PrintStream out, final int indent) {
+ for (int i = 0; i < indent; i++) {
+ out.print(INDENT_STRING);
+ }
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Puts all the keys and values from the specified array into the map.
* <p>
- * This method returns a new sorted map (decorating the specified map) that
- * will transform any new entries added to it.
- * Existing entries in the specified map will not be transformed.
- * If you want that behaviour, see {@link TransformedSortedMap#transformedSortedMap}.
+ * This method is an alternative to the {@link java.util.Map#putAll(java.util.Map)} method and constructors. It
+ * allows you to build a map from an object array of various possible styles.
+ * </p>
* <p>
- * Each object is passed through the transformers as it is added to the
- * Map. It is important not to use the original map after invoking this
- * method, as it is a backdoor for adding untransformed objects.
+ * If the first entry in the object array implements {@link java.util.Map.Entry} or {@link KeyValue} then the key
+ * and value are added from that object. If the first entry in the object array is an object array itself, then it
+ * is assumed that index 0 in the sub-array is the key and index 1 is the value. Otherwise, the array is treated as
+ * keys and values in alternate indices.
+ * </p>
* <p>
- * If there are any elements already in the map being decorated, they
- * are NOT transformed.
+ * For example, to create a color map:
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to transform, must not be null, typically empty
- * @param keyTransformer the transformer for the map keys, null means no transformation
- * @param valueTransformer the transformer for the map values, null means no transformation
- * @return a transformed map backed by the given map
- * @throws NullPointerException if the SortedMap is null
+ * <pre>
+ * Map colorMap = MapUtils.putAll(new HashMap(),
+ * new String[][] { { "RED", "#FF0000" }, { "GREEN", "#00FF00" }, { "BLUE", "#0000FF" } });
+ * </pre>
+ *
+ * <p>
+ * or:
+ * </p>
+ *
+ * <pre>
+ * Map colorMap = MapUtils.putAll(new HashMap(),
+ * new String[] { "RED", "#FF0000", "GREEN", "#00FF00", "BLUE", "#0000FF" });
+ * </pre>
+ *
+ * <p>
+ * or:
+ * </p>
+ *
+ * <pre>
+ * Map colorMap = MapUtils.putAll(new HashMap(), new Map.Entry[] { new DefaultMapEntry("RED", "#FF0000"),
+ * new DefaultMapEntry("GREEN", "#00FF00"), new DefaultMapEntry("BLUE", "#0000FF") });
+ * </pre>
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to populate, must not be null
+ * @param array an array to populate from, null ignored
+ * @return the input map
+ * @throws NullPointerException if map is null
+ * @throws IllegalArgumentException if sub-array or entry matching used and an entry is invalid
+ * @throws ClassCastException if the array contents is mixed
+ * @since 3.2
*/
- public static <K, V> SortedMap<K, V> transformedSortedMap(final SortedMap<K, V> map,
- final Transformer<? super K, ? extends K> keyTransformer,
- final Transformer<? super V, ? extends V> valueTransformer) {
- return TransformedSortedMap.transformingSortedMap(map, keyTransformer, valueTransformer);
+ @SuppressWarnings("unchecked") // As per Javadoc throws CCE for invalid array contents
+ public static <K, V> Map<K, V> putAll(final Map<K, V> map, final Object[] array) {
+ if (map == null) {
+ throw new NullPointerException("The map must not be null");
+ }
+ if (array == null || array.length == 0) {
+ return map;
+ }
+ final Object obj = array[0];
+ if (obj instanceof Map.Entry) {
+ for (final Object element : array) {
+ // cast ok here, type is checked above
+ final Map.Entry<K, V> entry = (Map.Entry<K, V>) element;
+ map.put(entry.getKey(), entry.getValue());
+ }
+ } else if (obj instanceof KeyValue) {
+ for (final Object element : array) {
+ // cast ok here, type is checked above
+ final KeyValue<K, V> keyval = (KeyValue<K, V>) element;
+ map.put(keyval.getKey(), keyval.getValue());
+ }
+ } else if (obj instanceof Object[]) {
+ for (int i = 0; i < array.length; i++) {
+ final Object[] sub = (Object[]) array[i];
+ if (sub == null || sub.length < 2) {
+ throw new IllegalArgumentException("Invalid array element: " + i);
+ }
+ // these casts can fail if array has incorrect types
+ map.put((K) sub[0], (V) sub[1]);
+ }
+ } else {
+ for (int i = 0; i < array.length - 1;) {
+ // these casts can fail if array has incorrect types
+ map.put((K) array[i++], (V) array[i++]);
+ }
+ }
+ return map;
}
/**
- * Returns a fixed-sized sorted map backed by the given sorted map.
- * Elements may not be added or removed from the returned map, but
- * existing elements can be changed (for instance, via the
- * {@link Map#put(Object,Object)} method).
+ * Protects against adding null values to a map.
+ * <p>
+ * This method checks the value being added to the map, and if it is null it is replaced by an empty string.
+ * </p>
+ * <p>
+ * This could be useful if the map does not accept null values, or for receiving data from a source that may provide
+ * null or empty string which should be held in the same way in the map.
+ * </p>
+ * <p>
+ * Keys are not validated. Note that this method can be used to circumvent the map's value type at runtime.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map whose size to fix, must not be null
- * @return a fixed-size map backed by that map
- * @throws NullPointerException if the SortedMap is null
+ * @param <K> the key type
+ * @param map the map to add to, may not be null
+ * @param key the key
+ * @param value the value, null converted to ""
+ * @throws NullPointerException if the map is null
*/
- public static <K, V> SortedMap<K, V> fixedSizeSortedMap(final SortedMap<K, V> map) {
- return FixedSizeSortedMap.fixedSizeSortedMap(map);
+ public static <K> void safeAddToMap(final Map<? super K, Object> map, final K key, final Object value)
+ throws NullPointerException {
+ map.put(key, value == null ? "" : value);
}
/**
- * Returns a "lazy" sorted map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key.
+ * Gets the given map size or 0 if the map is null
+ *
+ * @param map a Map or null
+ * @return the given map size or 0 if the map is null
+ */
+ public static int size(final Map<?, ?> map) {
+ return map == null ? 0 : map.size();
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Returns a synchronized map backed by the given map.
* <p>
- * For instance:
+ * You must manually synchronize on the returned buffer's iterator to avoid non-deterministic behavior:
+ * </p>
*
* <pre>
- * Factory factory = new Factory() {
- * public Object create() {
- * return new Date();
+ * Map m = MapUtils.synchronizedMap(myMap);
+ * Set s = m.keySet(); // outside synchronized block
+ * synchronized (m) { // synchronized on MAP!
+ * Iterator i = s.iterator();
+ * while (i.hasNext()) {
+ * process(i.next());
* }
* }
- * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
- * Object obj = lazy.get("test");
* </pre>
*
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
- * instance is the value for the <code>"test"</code> key.
+ * <p>
+ * This method uses the implementation in {@link java.util.Collections Collections}.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to make lazy, must not be null
- * @param factory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws NullPointerException if the SortedMap or Factory is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to synchronize, must not be null
+ * @return a synchronized map backed by the given map
*/
- public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map, final Factory<? extends V> factory) {
- return LazySortedMap.lazySortedMap(map, factory);
+ public static <K, V> Map<K, V> synchronizedMap(final Map<K, V> map) {
+ return Collections.synchronizedMap(map);
}
+ // -----------------------------------------------------------------------
/**
- * Returns a "lazy" sorted map whose values will be created on demand.
- * <p>
- * When the key passed to the returned map's {@link Map#get(Object)}
- * method is not present in the map, then the factory will be used
- * to create a new object and that object will become the value
- * associated with that key. The factory is a {@link Transformer}
- * that will be passed the key which it must transform into the value.
+ * Returns a synchronized sorted map backed by the given sorted map.
* <p>
- * For instance:
+ * You must manually synchronize on the returned buffer's iterator to avoid non-deterministic behavior:
+ * </p>
+ *
* <pre>
- * Transformer factory = new Transformer() {
- * public Object transform(Object mapKey) {
- * return new File(mapKey);
+ * Map m = MapUtils.synchronizedSortedMap(myMap);
+ * Set s = m.keySet(); // outside synchronized block
+ * synchronized (m) { // synchronized on MAP!
+ * Iterator i = s.iterator();
+ * while (i.hasNext()) {
+ * process(i.next());
* }
* }
- * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
- * Object obj = lazy.get("C:/dev");
* </pre>
*
- * After the above code is executed, <code>obj</code> will contain
- * a new <code>File</code> instance for the C drive dev directory.
- * Furthermore, that <code>File</code> instance is the value for the
- * <code>"C:/dev"</code> key in the map.
* <p>
- * If a lazy map is wrapped by a synchronized map, the result is a simple
- * synchronized cache. When an object is not is the cache, the cache itself
- * calls back to the factory Transformer to populate itself, all within the
- * same synchronized block.
+ * This method uses the implementation in {@link java.util.Collections Collections}.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the map to make lazy, must not be null
- * @param transformerFactory the factory for creating new objects, must not be null
- * @return a lazy map backed by the given map
- * @throws NullPointerException if the Map or Transformer is null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to synchronize, must not be null
+ * @return a synchronized map backed by the given map
+ * @throws NullPointerException if the map is null
*/
- public static <K, V> SortedMap<K, V> lazySortedMap(final SortedMap<K, V> map,
- final Transformer<? super K, ? extends V> transformerFactory) {
- return LazySortedMap.lazySortedMap(map, transformerFactory);
+ public static <K, V> SortedMap<K, V> synchronizedSortedMap(final SortedMap<K, V> map) {
+ return Collections.synchronizedSortedMap(map);
}
/**
- * Populates a Map using the supplied <code>Transformer</code> to transform the elements
- * into keys, using the unaltered element as the value in the <code>Map</code>.
+ * Creates a new HashMap using data copied from a ResourceBundle.
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the <code>Map</code> to populate.
- * @param elements the <code>Iterable</code> containing the input values for the map.
- * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
- * @throws NullPointerException if the map, elements or transformer are null
+ * @param resourceBundle the resource bundle to convert, may not be null
+ * @return the hashmap containing the data
+ * @throws NullPointerException if the bundle is null
*/
- public static <K, V> void populateMap(final Map<K, V> map, final Iterable<? extends V> elements,
- final Transformer<V, K> keyTransformer) {
- populateMap(map, elements, keyTransformer, TransformerUtils.<V>nopTransformer());
+ public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
+ final Enumeration<String> enumeration = resourceBundle.getKeys();
+ final Map<String, Object> map = new HashMap<>();
+
+ while (enumeration.hasMoreElements()) {
+ final String key = enumeration.nextElement();
+ final Object value = resourceBundle.getObject(key);
+ map.put(key, value);
+ }
+
+ return map;
}
+ // -------------------------------------------------------------------------
/**
- * Populates a Map using the supplied <code>Transformer</code>s to transform the elements
- * into keys and values.
+ * Gets a new Properties object initialised with the values from a Map. A null input will return an empty properties
+ * object.
+ * <p>
+ * A Properties object may only store non-null keys and values, thus if the provided map contains either a key or
+ * value which is {@code null}, a {@link NullPointerException} will be thrown.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param <E> the type of object contained in the {@link Iterable}
- * @param map the <code>Map</code> to populate.
- * @param elements the <code>Iterable</code> containing the input values for the map.
- * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
- * @param valueTransformer the <code>Transformer</code> used to transform the element into a value
- * @throws NullPointerException if the map, elements or transformers are null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to convert to a Properties object
+ * @return the properties object
+ * @throws NullPointerException if a key or value in the provided map is {@code null}
*/
- public static <K, V, E> void populateMap(final Map<K, V> map, final Iterable<? extends E> elements,
- final Transformer<E, K> keyTransformer,
- final Transformer<E, V> valueTransformer) {
- final Iterator<? extends E> iter = elements.iterator();
- while (iter.hasNext()) {
- final E temp = iter.next();
- map.put(keyTransformer.transform(temp), valueTransformer.transform(temp));
+ public static <K, V> Properties toProperties(final Map<K, V> map) {
+ final Properties answer = new Properties();
+ if (map != null) {
+ for (final Entry<K, V> entry2 : map.entrySet()) {
+ final Map.Entry<?, ?> entry = entry2;
+ final Object key = entry.getKey();
+ final Object value = entry.getValue();
+ answer.put(key, value);
+ }
}
+ return answer;
}
/**
- * Populates a MultiMap using the supplied <code>Transformer</code> to transform the elements
- * into keys, using the unaltered element as the value in the <code>MultiMap</code>.
+ * Returns a transformed map backed by the given map.
+ * <p>
+ * This method returns a new map (decorating the specified map) that will transform any new entries added to it.
+ * Existing entries in the specified map will not be transformed. If you want that behaviour, see
+ * {@link TransformedMap#transformedMap}.
+ * </p>
+ * <p>
+ * Each object is passed through the transformers as it is added to the Map. It is important not to use the original
+ * map after invoking this method, as it is a backdoor for adding untransformed objects.
+ * </p>
+ * <p>
+ * If there are any elements already in the map being decorated, they are NOT transformed.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map the <code>MultiMap</code> to populate.
- * @param elements the <code>Iterable</code> to use as input values for the map.
- * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
- * @throws NullPointerException if the map, elements or transformer are null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to transform, must not be null, typically empty
+ * @param keyTransformer the transformer for the map keys, null means no transformation
+ * @param valueTransformer the transformer for the map values, null means no transformation
+ * @return a transformed map backed by the given map
+ * @throws NullPointerException if the Map is null
*/
- public static <K, V> void populateMap(final MultiMap<K, V> map, final Iterable<? extends V> elements,
- final Transformer<V, K> keyTransformer) {
- populateMap(map, elements, keyTransformer, TransformerUtils.<V>nopTransformer());
+ public static <K, V> IterableMap<K, V> transformedMap(final Map<K, V> map,
+ final Transformer<? super K, ? extends K> keyTransformer,
+ final Transformer<? super V, ? extends V> valueTransformer) {
+ return TransformedMap.transformingMap(map, keyTransformer, valueTransformer);
}
/**
- * Populates a MultiMap using the supplied <code>Transformer</code>s to transform the elements
- * into keys and values.
+ * Returns a transformed sorted map backed by the given map.
+ * <p>
+ * This method returns a new sorted map (decorating the specified map) that will transform any new entries added to
+ * it. Existing entries in the specified map will not be transformed. If you want that behaviour, see
+ * {@link TransformedSortedMap#transformedSortedMap}.
+ * </p>
+ * <p>
+ * Each object is passed through the transformers as it is added to the Map. It is important not to use the original
+ * map after invoking this method, as it is a backdoor for adding untransformed objects.
+ * </p>
+ * <p>
+ * If there are any elements already in the map being decorated, they are NOT transformed.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param <E> the type of object contained in the {@link Iterable}
- * @param map the <code>MultiMap</code> to populate.
- * @param elements the <code>Iterable</code> containing the input values for the map.
- * @param keyTransformer the <code>Transformer</code> used to transform the element into a key value
- * @param valueTransformer the <code>Transformer</code> used to transform the element into a value
- * @throws NullPointerException if the map, collection or transformers are null
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to transform, must not be null, typically empty
+ * @param keyTransformer the transformer for the map keys, null means no transformation
+ * @param valueTransformer the transformer for the map values, null means no transformation
+ * @return a transformed map backed by the given map
+ * @throws NullPointerException if the SortedMap is null
*/
- public static <K, V, E> void populateMap(final MultiMap<K, V> map, final Iterable<? extends E> elements,
- final Transformer<E, K> keyTransformer,
- final Transformer<E, V> valueTransformer) {
- final Iterator<? extends E> iter = elements.iterator();
- while (iter.hasNext()) {
- final E temp = iter.next();
- map.put(keyTransformer.transform(temp), valueTransformer.transform(temp));
- }
+ public static <K, V> SortedMap<K, V> transformedSortedMap(final SortedMap<K, V> map,
+ final Transformer<? super K, ? extends K> keyTransformer,
+ final Transformer<? super V, ? extends V> valueTransformer) {
+ return TransformedSortedMap.transformingSortedMap(map, keyTransformer, valueTransformer);
}
/**
- * Get the specified {@link Map} as an {@link IterableMap}.
+ * Returns an unmodifiable map backed by the given map.
+ * <p>
+ * This method uses the implementation in the decorators subpackage.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param map to wrap if necessary.
- * @return IterableMap<K, V>
- * @throws NullPointerException if map is null
- * @since 4.0
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the map to make unmodifiable, must not be null
+ * @return an unmodifiable map backed by the given map
+ * @throws NullPointerException if the map is null
*/
- public static <K, V> IterableMap<K, V> iterableMap(final Map<K, V> map) {
- if (map == null) {
- throw new NullPointerException("Map must not be null");
- }
- return map instanceof IterableMap ? (IterableMap<K, V>) map : new AbstractMapDecorator<K, V>(map) {};
+ public static <K, V> Map<K, V> unmodifiableMap(final Map<? extends K, ? extends V> map) {
+ return UnmodifiableMap.unmodifiableMap(map);
}
/**
- * Get the specified {@link SortedMap} as an {@link IterableSortedMap}.
+ * Returns an unmodifiable sorted map backed by the given sorted map.
+ * <p>
+ * This method uses the implementation in the decorators subpackage.
+ * </p>
*
- * @param <K> the key type
- * @param <V> the value type
- * @param sortedMap to wrap if necessary
- * @return {@link IterableSortedMap}<K, V>
- * @throws NullPointerException if sortedMap is null
- * @since 4.0
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param map the sorted map to make unmodifiable, must not be null
+ * @return an unmodifiable map backed by the given map
+ * @throws NullPointerException if the map is null
*/
- public static <K, V> IterableSortedMap<K, V> iterableSortedMap(final SortedMap<K, V> sortedMap) {
- if (sortedMap == null) {
- throw new NullPointerException("Map must not be null");
+ public static <K, V> SortedMap<K, V> unmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
+ return UnmodifiableSortedMap.unmodifiableSortedMap(map);
+ }
+
+ // Printing methods
+ // -------------------------------------------------------------------------
+ /**
+ * Prints the given map with nice line breaks.
+ * <p>
+ * This method prints a nicely formatted String describing the Map. Each map entry will be printed with key and
+ * value. When the value is a Map, recursive behaviour occurs.
+ * </p>
+ * <p>
+ * This method is NOT thread-safe in any special way. You must manually synchronize on either this class or the
+ * stream as required.
+ * </p>
+ *
+ * @param out the stream to print to, must not be null
+ * @param label The label to be used, may be <code>null</code>. If <code>null</code>, the label is not output. It
+ * typically represents the name of the property in a bean or similar.
+ * @param map The map to print, may be <code>null</code>. If <code>null</code>, the text 'null' is output.
+ * @throws NullPointerException if the stream is <code>null</code>
+ */
+ public static void verbosePrint(final PrintStream out, final Object label, final Map<?, ?> map) {
+ verbosePrintInternal(out, label, map, new ArrayDeque<Map<?, ?>>(), false);
+ }
+
+ /**
+ * Implementation providing functionality for {@link #debugPrint} and for {@link #verbosePrint}. This prints the
+ * given map with nice line breaks. If the debug flag is true, it additionally prints the type of the object value.
+ * If the contents of a map include the map itself, then the text <em>(this Map)</em> is printed out. If the
+ * contents include a parent container of the map, the text <em>(ancestor[i] Map)</em> is printed, where i actually
+ * indicates the number of levels which must be traversed in the sequential list of ancestors (e.g. father,
+ * grandfather, great-grandfather, etc).
+ *
+ * @param out the stream to print to
+ * @param label the label to be used, may be <code>null</code>. If <code>null</code>, the label is not output. It
+ * typically represents the name of the property in a bean or similar.
+ * @param map the map to print, may be <code>null</code>. If <code>null</code>, the text 'null' is output
+ * @param lineage a stack consisting of any maps in which the previous argument is contained. This is checked to
+ * avoid infinite recursion when printing the output
+ * @param debug flag indicating whether type names should be output.
+ * @throws NullPointerException if the stream is <code>null</code>
+ */
+ private static void verbosePrintInternal(final PrintStream out, final Object label, final Map<?, ?> map,
+ final Deque<Map<?, ?>> lineage, final boolean debug) {
+ printIndent(out, lineage.size());
+
+ if (map == null) {
+ if (label != null) {
+ out.print(label);
+ out.print(" = ");
+ }
+ out.println("null");
+ return;
+ }
+ if (label != null) {
+ out.print(label);
+ out.println(" = ");
}
- return sortedMap instanceof IterableSortedMap ? (IterableSortedMap<K, V>) sortedMap :
- new AbstractSortedMapDecorator<K, V>(sortedMap) {};
+
+ printIndent(out, lineage.size());
+ out.println("{");
+
+ lineage.addLast(map);
+
+ for (final Map.Entry<?, ?> entry : map.entrySet()) {
+ final Object childKey = entry.getKey();
+ final Object childValue = entry.getValue();
+ if (childValue instanceof Map && !lineage.contains(childValue)) {
+ verbosePrintInternal(out, childKey == null ? "null" : childKey, (Map<?, ?>) childValue, lineage, debug);
+ } else {
+ printIndent(out, lineage.size());
+ out.print(childKey);
+ out.print(" = ");
+
+ final int lineageIndex = IterableUtils.indexOf(lineage, PredicateUtils.equalPredicate(childValue));
+ if (lineageIndex == -1) {
+ out.print(childValue);
+ } else if (lineage.size() - 1 == lineageIndex) {
+ out.print("(this Map)");
+ } else {
+ out.print("(ancestor[" + (lineage.size() - 1 - lineageIndex - 1) + "] Map)");
+ }
+
+ if (debug && childValue != null) {
+ out.print(' ');
+ out.println(childValue.getClass().getName());
+ } else {
+ out.println();
+ }
+ }
+ }
+
+ lineage.removeLast();
+
+ printIndent(out, lineage.size());
+ out.println(debug ? "} " + map.getClass().getName() : "}");
}
/**
- * Gets the given map size or 0 if the map is null
- * @param map a Map or null
- * @return the given map size or 0 if the map is null
+ * <code>MapUtils</code> should not normally be instantiated.
*/
- public static int size(final Map<?, ?> map) {
- return map == null ? 0 : map.size();
+ private MapUtils() {
}
}
diff --git a/src/test/java/org/apache/commons/collections4/MapUtilsTest.java b/src/test/java/org/apache/commons/collections4/MapUtilsTest.java
index 676a3ab..9a2470c 100644
--- a/src/test/java/org/apache/commons/collections4/MapUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/MapUtilsTest.java
@@ -39,6 +39,7 @@ import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
+import java.util.function.Function;
import org.apache.commons.collections4.collection.TransformedCollectionTest;
import org.apache.commons.collections4.junit.AbstractAvailableLocalesTest;
@@ -182,9 +183,9 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
// sub array
test = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
- {"RED", "#FF0000"},
- {"GREEN", "#00FF00"},
- {"BLUE", "#0000FF"}
+ {"RED", "#FF0000"},
+ {"GREEN", "#00FF00"},
+ {"BLUE", "#0000FF"}
});
assertEquals(true, test.containsKey("RED"));
assertEquals("#FF0000", test.get("RED"));
@@ -196,36 +197,36 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
try {
MapUtils.putAll(new HashMap<String, String>(), new String[][] {
- {"RED", "#FF0000"},
- null,
- {"BLUE", "#0000FF"}
+ {"RED", "#FF0000"},
+ null,
+ {"BLUE", "#0000FF"}
});
fail();
} catch (final IllegalArgumentException ex) {}
try {
MapUtils.putAll(new HashMap<String, String>(), new String[][] {
- {"RED", "#FF0000"},
- {"GREEN"},
- {"BLUE", "#0000FF"}
+ {"RED", "#FF0000"},
+ {"GREEN"},
+ {"BLUE", "#0000FF"}
});
fail();
} catch (final IllegalArgumentException ex) {}
try {
MapUtils.putAll(new HashMap<String, String>(), new String[][] {
- {"RED", "#FF0000"},
- {},
- {"BLUE", "#0000FF"}
+ {"RED", "#FF0000"},
+ {},
+ {"BLUE", "#0000FF"}
});
fail();
} catch (final IllegalArgumentException ex) {}
// flat array
test = MapUtils.putAll(new HashMap<String, String>(), new String[] {
- "RED", "#FF0000",
- "GREEN", "#00FF00",
- "BLUE", "#0000FF"
+ "RED", "#FF0000",
+ "GREEN", "#00FF00",
+ "BLUE", "#0000FF"
});
assertEquals(true, test.containsKey("RED"));
assertEquals("#FF0000", test.get("RED"));
@@ -236,10 +237,10 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(3, test.size());
test = MapUtils.putAll(new HashMap<String, String>(), new String[] {
- "RED", "#FF0000",
- "GREEN", "#00FF00",
- "BLUE", "#0000FF",
- "PURPLE" // ignored
+ "RED", "#FF0000",
+ "GREEN", "#00FF00",
+ "BLUE", "#0000FF",
+ "PURPLE" // ignored
});
assertEquals(true, test.containsKey("RED"));
assertEquals("#FF0000", test.get("RED"));
@@ -254,9 +255,9 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
// map entry
test = MapUtils.putAll(new HashMap<String, String>(), new Object[] {
- new DefaultMapEntry<>("RED", "#FF0000"),
- new DefaultMapEntry<>("GREEN", "#00FF00"),
- new DefaultMapEntry<>("BLUE", "#0000FF")
+ new DefaultMapEntry<>("RED", "#FF0000"),
+ new DefaultMapEntry<>("GREEN", "#00FF00"),
+ new DefaultMapEntry<>("BLUE", "#0000FF")
});
assertEquals(true, test.containsKey("RED"));
assertEquals("#FF0000", test.get("RED"));
@@ -268,9 +269,9 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
// key value
test = MapUtils.putAll(new HashMap<String, String>(), new Object[] {
- new DefaultKeyValue<>("RED", "#FF0000"),
- new DefaultKeyValue<>("GREEN", "#00FF00"),
- new DefaultKeyValue<>("BLUE", "#0000FF")
+ new DefaultKeyValue<>("RED", "#FF0000"),
+ new DefaultKeyValue<>("GREEN", "#00FF00"),
+ new DefaultKeyValue<>("BLUE", "#0000FF")
});
assertEquals(true, test.containsKey("RED"));
assertEquals("#FF0000", test.get("RED"));
@@ -953,9 +954,17 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(2.0, MapUtils.getDoubleValue(in,"key", 0.0), 0);
assertEquals(2.0, MapUtils.getDoubleValue(in,"key"), 0);
assertEquals(1.0, MapUtils.getDoubleValue(in,"noKey", 1.0), 0);
+ assertEquals(5.0, MapUtils.getDoubleValue(in,"noKey", (key)->{
+ //sometimes the default value need to be calculated,such as System.currentTimeMillis()
+ return 5.0D;
+ }),0);
+
assertEquals(0, MapUtils.getDoubleValue(in,"noKey"), 0);
assertEquals(2.0, MapUtils.getDouble(in,"key", 0.0), 0);
assertEquals(1.0, MapUtils.getDouble(in,"noKey", 1.0), 0);
+ assertEquals(1.0, MapUtils.getDouble(in,"noKey", (key)->{
+ return 1.0;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
@@ -973,9 +982,15 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(2.0, MapUtils.getFloatValue(in,"key", 0.0f), 0);
assertEquals(2.0, MapUtils.getFloatValue(in,"key"), 0);
assertEquals(1.0, MapUtils.getFloatValue(in,"noKey", 1.0f), 0);
+ assertEquals(1.0, MapUtils.getFloatValue(in,"noKey", (key)->{
+ return 1.0F;
+ }), 0);
assertEquals(0, MapUtils.getFloatValue(in,"noKey"), 0);
assertEquals(2.0, MapUtils.getFloat(in,"key", 0.0f), 0);
assertEquals(1.0, MapUtils.getFloat(in,"noKey", 1.0f), 0);
+ assertEquals(1.0, MapUtils.getFloat(in,"noKey", (key)->{
+ return 1.0F;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
final char decimalSeparator = getDecimalSeparator();
@@ -992,9 +1007,15 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(2.0, MapUtils.getLongValue(in,"key", 0L), 0);
assertEquals(2.0, MapUtils.getLongValue(in,"key"), 0);
assertEquals(1, MapUtils.getLongValue(in,"noKey", 1L), 0);
+ assertEquals(1, MapUtils.getLongValue(in,"noKey", (key)->{
+ return 1L;
+ }), 0);
assertEquals(0, MapUtils.getLongValue(in,"noKey"), 0);
assertEquals(2.0, MapUtils.getLong(in,"key", 0L), 0);
assertEquals(1, MapUtils.getLong(in,"noKey", 1L), 0);
+ assertEquals(1, MapUtils.getLong(in,"noKey", (key)->{
+ return 1L;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
inStr.put("str1", "2");
@@ -1012,9 +1033,15 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(2, MapUtils.getIntValue(in,"key", 0), 0);
assertEquals(2, MapUtils.getIntValue(in,"key"), 0);
assertEquals(0, MapUtils.getIntValue(in,"noKey", 0), 0);
+ assertEquals(0, MapUtils.getIntValue(in,"noKey", (key)->{
+ return 0;
+ }), 0);
assertEquals(0, MapUtils.getIntValue(in,"noKey"), 0);
assertEquals(2, MapUtils.getInteger(in,"key", 0), 0);
assertEquals(0, MapUtils.getInteger(in,"noKey", 0), 0);
+ assertEquals(0, MapUtils.getInteger(in,"noKey", (key)->{
+ return 0;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
inStr.put("str1", "2");
@@ -1031,9 +1058,15 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(val, MapUtils.getShortValue(in,"key", val), 0);
assertEquals(val, MapUtils.getShortValue(in,"key"), 0);
assertEquals(val, MapUtils.getShortValue(in,"noKey", val), 0);
+ assertEquals(val, MapUtils.getShortValue(in,"noKey", (key)->{
+ return val;
+ }), 0);
assertEquals(0, MapUtils.getShortValue(in,"noKey"), 0);
assertEquals(val, MapUtils.getShort(in,"key", val), 0);
assertEquals(val,MapUtils.getShort(in,"noKey", val), 0);
+ assertEquals(val,MapUtils.getShort(in,"noKey", (key)->{
+ return val;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
inStr.put("str1", "10");
@@ -1050,9 +1083,15 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(val, MapUtils.getByteValue(in,"key", val), 0);
assertEquals(val, MapUtils.getByteValue(in,"key"), 0);
assertEquals(val, MapUtils.getByteValue(in,"noKey", val), 0);
+ assertEquals(val, MapUtils.getByteValue(in,"noKey", (key)->{
+ return (byte)100;
+ }), 0);
assertEquals(0, MapUtils.getByteValue(in,"noKey"), 0);
assertEquals(val, MapUtils.getByte(in,"key", val), 0);
assertEquals(val, MapUtils.getByte(in,"noKey", val), 0);
+ assertEquals(val, MapUtils.getByte(in,"noKey", (key)->{
+ return val;
+ }), 0);
final Map<String, String> inStr = new HashMap<>();
@@ -1069,6 +1108,13 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(val.intValue(), MapUtils.getNumber(in,"key", val).intValue(), 0);
assertEquals(val.intValue(), MapUtils.getNumber(in,"noKey", val).intValue(), 0);
+ assertEquals(val.intValue(), MapUtils.getNumber(in,"noKey", (key)->{
+ if (true) {
+ return val;
+ } else {
+ return null;
+ }
+ }).intValue(), 0);
}
@@ -1081,6 +1127,13 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals("str", MapUtils.getString(in,"key"));
assertEquals(null, MapUtils.getString(null,"key"));
assertEquals("default", MapUtils.getString(in,"noKey", "default"));
+ assertEquals("default", MapUtils.getString(in,"noKey", (key)->{
+ if ("noKey".equals(key)) {
+ return "default";
+ } else {
+ return "";
+ }
+ }));
assertEquals("default", MapUtils.getString(null,"noKey", "default"));
}
@@ -1095,7 +1148,6 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertEquals(null, MapUtils.getObject(null,"key"));
assertEquals("default", MapUtils.getObject(in,"noKey", "default"));
assertEquals("default", MapUtils.getObject(null,"noKey", "default"));
-
}
@Test
@@ -1106,9 +1158,19 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
assertTrue(MapUtils.getBooleanValue(in,"key", true));
assertTrue(MapUtils.getBooleanValue(in,"key"));
assertTrue(MapUtils.getBooleanValue(in,"noKey", true));
+ assertTrue(MapUtils.getBooleanValue(in,"noKey", (key)->{
+ return true;
+ }));
assertTrue(!MapUtils.getBooleanValue(in,"noKey"));
assertTrue(MapUtils.getBoolean(in,"key", true));
assertTrue(MapUtils.getBoolean(in,"noKey", true));
+ assertTrue(MapUtils.getBoolean(in,"noKey", (key)->{
+ if (System.currentTimeMillis() > 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }));
assertEquals(null, MapUtils.getBoolean(null,"noKey"));
@@ -1128,12 +1190,12 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
final Map<String, String> valMap = new HashMap<>();
valMap.put("key1", "value1");
in.put("key1", valMap);
- final Map<?, ?> outValue = MapUtils.getMap(in,"key1", null);
+ final Map<?, ?> outValue = MapUtils.getMap(in,"key1", (Map<?, ?>) null);
assertEquals("value1", outValue.get("key1"));
assertEquals(null, outValue.get("key2"));
- assertEquals(null, MapUtils.getMap(in,"key2", null));
- assertEquals(null, MapUtils.getMap(null,"key2", null));
+ assertEquals(null, MapUtils.getMap(in, "key2", (Map<?, ?>) null));
+ assertEquals(null, MapUtils.getMap(null, "key2", (Map<?, ?>) null));
}
@Test
@@ -1149,9 +1211,9 @@ public class MapUtilsTest extends AbstractAvailableLocalesTest {
@Test
public void testOrderedMap() {
- final Map<String, String> inMap = new HashMap<>();
- inMap.put("key1", "value1");
- inMap.put("key2", "value2");
+ final Map<String, String> inMap = new HashMap<>();
+ inMap.put("key1", "value1");
+ inMap.put("key2", "value2");
final Map<String, String> map = MapUtils.orderedMap(inMap);
assertTrue("returned object should be a OrderedMap", map instanceof OrderedMap);
}