com.landawn.abacus.util.Maps Maven / Gradle / Ivy
/*
* Copyright (C) 2019 HaiYang Li
*
* Licensed 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.
*/
package com.landawn.abacus.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.MayReturnNull;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.BeanInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.Fn.Factory;
import com.landawn.abacus.util.Fn.IntFunctions;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalBoolean;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalFloat;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.u.OptionalShort;
/**
*
* Note: This class includes codes copied from Apache Commons Lang, Google Guava and other open source projects under the Apache License 2.0.
* The methods copied from other libraries/frameworks/projects may be modified in this class.
*
*
*
* Present -> key is found in the specified map with {@code non-null} value.
*
* Absent -> key is not found in the specified map or found with {@code null} value.
*
*
* When to throw exception? It's designed to avoid throwing any unnecessary
* exception if the contract defined by method is not broken. for example, if
* user tries to reverse a {@code null} or empty String. the input String will be
* returned. But exception will be thrown if try to add element to a {@code null} Object array or collection.
*
*
* An empty String/Array/Collection/Map/Iterator/Iterable/InputStream/Reader will always be a preferred choice than a {@code null} for the return value of a method.
*
*
* @see com.landawn.abacus.util.N
* @see com.landawn.abacus.util.Iterables
* @see com.landawn.abacus.util.Iterators
* @see com.landawn.abacus.util.Strings
*/
public final class Maps {
private static final Object NONE = ClassUtil.createNullMask();
private Maps() {
// Utility class.
}
/**
* Returns an immutable/unmodifiable key set of the specified {@code map}.
* An empty immutable/unmodifiable set is returned if the specified {@code map} is {@code null} or empty.
*
* @param
* @param map
* @return
* @deprecated replaced by {@code N.nullToEmpty(map).keySet()}
* @see N#nullToEmpty(Map)
*/
@Deprecated
@Beta
public static ImmutableSet keys(final Map extends K, ?> map) {
return N.isEmpty(map) ? ImmutableSet.empty() : ImmutableSet.wrap(map.keySet());
}
/**
* Returns an immutable/unmodifiable value collection of the specified {@code map}.
* An empty immutable/unmodifiable collection is returned if the specified {@code map} is {@code null} or empty.
*
* @param
* @param map
* @return
* @deprecated replaced by {@code N.nullToEmpty(map).values()}
* @see N#nullToEmpty(Map)
*/
@Deprecated
@Beta
public static ImmutableCollection values(final Map, ? extends V> map) {
return N.isEmpty(map) ? ImmutableSet.empty() : ImmutableCollection.wrap(map.values());
}
/**
* Returns an immutable/unmodifiable entry set of the specified {@code map}.
* An empty immutable/unmodifiable entry set is returned if the specified {@code map} is {@code null} or empty.
*
* @param
* @param
* @param map
* @return
* @deprecated replaced by {@code N.nullToEmpty(map).entrySet()}
* @see N#nullToEmpty(Map)
*/
@Deprecated
@Beta
@SuppressWarnings({ "rawtypes" })
public static ImmutableSet> entrySet(final Map extends K, ? extends V> map) {
return N.isEmpty(map) ? ImmutableSet.empty() : ImmutableSet.wrap((Set) map.entrySet());
}
// /**
// *
// * @param
// * @param the key type
// * @param c
// * @param keyExtractor
// * @return
// */
// public static Map create(Iterable extends T> c, final Function super T, ? extends K> keyExtractor) {
// N.checkArgNotNull(keyExtractor);
//
// final Map result = N.newHashMap(c instanceof Collection ? ((Collection) c).size() : 0);
//
// for (T e : c) {
// result.put(keyExtractor.apply(e), e);
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param the key type
// * @param the value type
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @return
// */
// public static Map create(Iterable extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
//
// final Map result = N.newHashMap(c instanceof Collection ? ((Collection) c).size() : 0);
//
// for (T e : c) {
// result.put(keyExtractor.apply(e), valueExtractor.apply(e));
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param the key type
// * @param the value type
// * @param
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @param mapSupplier
// * @return
// */
// public static > M create(Iterable extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final IntFunction extends M> mapSupplier) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
// N.checkArgNotNull(mapSupplier);
//
// final M result = mapSupplier.apply(c instanceof Collection ? ((Collection) c).size() : 0);
//
// for (T e : c) {
// result.put(keyExtractor.apply(e), valueExtractor.apply(e));
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param
// * @param
// * @param
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @param mergeFunction
// * @param mapSupplier
// * @return
// */
// public static > M create(Iterable extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final BinaryOperator mergeFunction, final IntFunction extends M> mapSupplier) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
// N.checkArgNotNull(mergeFunction);
// N.checkArgNotNull(mapSupplier);
//
// final M result = mapSupplier.apply(c instanceof Collection ? ((Collection) c).size() : 0);
// K key = null;
//
// for (T e : c) {
// key = keyExtractor.apply(e);
//
// final V oldValue = result.get(key);
//
// if (oldValue == null && !result.containsKey(key)) {
// result.put(key, valueExtractor.apply(e));
// } else {
// result.put(key, mergeFunction.apply(oldValue, valueExtractor.apply(e)));
// }
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param the key type
// * @param iter
// * @param keyExtractor
// * @return
// */
// public static Map create(final Iterator extends T> iter, final Function super T, K> keyExtractor) {
// N.checkArgNotNull(keyExtractor);
//
// if (iter == null) {
// return new HashMap<>();
// }
//
// final Map result = new HashMap<>();
// T e = null;
//
// while (iter.hasNext()) {
// e = iter.next();
// result.put(keyExtractor.apply(e), e);
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param the key type
// * @param the value type
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @return
// */
// public static Map create(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
//
// if (iter == null) {
// return new HashMap<>();
// }
//
// final Map result = new HashMap<>();
// T e = null;
//
// while (iter.hasNext()) {
// e = iter.next();
// result.put(keyExtractor.apply(e), valueExtractor.apply(e));
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param the key type
// * @param the value type
// * @param
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @param mapSupplier
// * @return
// */
// public static > M create(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final Supplier extends M> mapSupplier) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
// N.checkArgNotNull(mapSupplier);
//
// if (iter == null) {
// return mapSupplier.get();
// }
//
// final M result = mapSupplier.get();
// T e = null;
//
// while (iter.hasNext()) {
// e = iter.next();
// result.put(keyExtractor.apply(e), valueExtractor.apply(e));
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param
// * @param
// * @param
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @param mergeFunction
// * @param mapSupplier
// * @return
// */
// public static > M create(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final BinaryOperator mergeFunction, final Supplier extends M> mapSupplier) {
// N.checkArgNotNull(keyExtractor);
// N.checkArgNotNull(valueExtractor);
// N.checkArgNotNull(mergeFunction);
// N.checkArgNotNull(mapSupplier);
//
// if (iter == null) {
// return mapSupplier.get();
// }
//
// final M result = mapSupplier.get();
// T e = null;
// K key = null;
//
// while (iter.hasNext()) {
// e = iter.next();
// key = keyExtractor.apply(e);
//
// final V oldValue = result.get(key);
//
// if (oldValue == null && !result.containsKey(key)) {
// result.put(key, valueExtractor.apply(e));
// } else {
// result.put(key, mergeFunction.apply(oldValue, valueExtractor.apply(e)));
// }
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param
// * @param
// * @param map
// * @param valueExtractor
// * @return
// */
// public static Map create(final Map extends K, ? extends V> map, final Function super V, V2> valueExtractor) {
// N.checkArgNotNull(valueExtractor);
//
// if (map == null) {
// return new HashMap<>();
// }
//
// final Map result = Maps.newTargetMap(map);
//
// for (Map.Entry extends K, ? extends V> entry : map.entrySet()) {
// result.put(entry.getKey(), valueExtractor.apply(entry.getValue()));
// }
//
// return result;
// }
//
// /**
// *
// * @param
// * @param
// * @param
// * @param
// * @param map
// * @param valueExtractor
// * @param mapSupplier
// * @return
// */
// public static > M create(final Map extends K, ? extends V> map, final Function super V, V2> valueExtractor,
// final IntFunction extends M> mapSupplier) {
// N.checkArgNotNull(valueExtractor);
// N.checkArgNotNull(mapSupplier);
//
// if (map == null) {
// return mapSupplier.apply(0);
// }
//
// final M result = mapSupplier.apply(map.size());
//
// for (Map.Entry extends K, ? extends V> entry : map.entrySet()) {
// result.put(entry.getKey(), valueExtractor.apply(entry.getValue()));
// }
//
// return result;
// }
// /**
// *
// *
// * @param
// * @param the key type
// * @param c
// * @param keyExtractor
// * @return
// * @deprecated Use {@link #create(Collection extends T>,Function super T, ? extends K>)} instead
// */
// @Deprecated
// public static Map newMap(Collection extends T> c, final Function super T, ? extends K> keyExtractor) {
// return create(c, keyExtractor);
// }
//
// /**
// *
// *
// * @param
// * @param the key type
// * @param the value type
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @return
// * @deprecated Use {@link #create(Collection extends T>,Function super T, ? extends K>,Function super T, ? extends V>)} instead
// */
// @Deprecated
// public static Map newMap(Collection extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor) {
// return create(c, keyExtractor, valueExtractor);
// }
//
// /**
// *
// *
// * @param
// * @param the key type
// * @param the value type
// * @param
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @param mapSupplier
// * @return
// * @deprecated Use {@link #create(Collection extends T>,Function super T, ? extends K>,Function super T, ? extends V>,IntFunction extends M>)} instead
// */
// @Deprecated
// public static > M newMap(Collection extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final IntFunction extends M> mapSupplier) {
// return create(c, keyExtractor, valueExtractor, mapSupplier);
// }
//
// /**
// *
// *
// * @param
// * @param
// * @param
// * @param
// * @param c
// * @param keyExtractor
// * @param valueExtractor
// * @param mergeFunction
// * @param mapSupplier
// * @return
// * @deprecated Use {@link #create(Collection extends T>,Function super T, ? extends K>,Function super T, ? extends V>,BinaryOperator,IntFunction extends M>)} instead
// */
// @Deprecated
// public static > M newMap(Collection extends T> c, final Function super T, ? extends K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final BinaryOperator mergeFunction, final IntFunction extends M> mapSupplier) {
// return create(c, keyExtractor, valueExtractor, mergeFunction, mapSupplier);
// }
//
// /**
// *
// *
// * @param
// * @param the key type
// * @param iter
// * @param keyExtractor
// * @return
// * @deprecated Use {@link #create(Iterator extends T>,Function super T, K, E>)} instead
// */
// @Deprecated
// public static Map newMap(final Iterator extends T> iter, final Function super T, K> keyExtractor) {
// return create(iter, keyExtractor);
// }
//
// /**
// *
// *
// * @param
// * @param the key type
// * @param the value type
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @return
// * @deprecated Use {@link #create(Iterator extends T>,Function super T, K, E>,Function super T, ? extends V>)} instead
// */
// @Deprecated
// public static Map newMap(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor) {
// return create(iter, keyExtractor, valueExtractor);
// }
//
// /**
// *
// *
// * @param
// * @param the key type
// * @param the value type
// * @param
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @param mapSupplier
// * @return
// * @deprecated Use {@link #create(Iterator extends T>,Function super T, K, E>,Function super T, ? extends V>,Supplier extends M>)} instead
// */
// @Deprecated
// public static > M newMap(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final Supplier extends M> mapSupplier) {
// return create(iter, keyExtractor, valueExtractor, mapSupplier);
// }
//
// /**
// *
// *
// * @param
// * @param
// * @param
// * @param
// * @param iter
// * @param keyExtractor
// * @param valueExtractor
// * @param mergeFunction
// * @param mapSupplier
// * @return
// * @deprecated Use {@link #create(Iterator extends T>,Function super T, K, E>,Function super T, ? extends V>,BinaryOperator,Supplier extends M>)} instead
// */
// @Deprecated
// public static > M newMap(final Iterator extends T> iter, final Function super T, K> keyExtractor,
// final Function super T, ? extends V> valueExtractor, final BinaryOperator mergeFunction, final Supplier extends M> mapSupplier) {
// return create(iter, keyExtractor, valueExtractor, mergeFunction, mapSupplier);
// }
/**
* Creates a new entry (key-value pair) with the provided key and value.
*
* This method generates a new entry using the provided key and value.
* The created entry is mutable, meaning that its key and value can be changed after creation.
*
* @param key The key of the new entry.
* @param value The value of the new entry.
* @return A new Entry with the provided key and value.
* @deprecated replaced by {@link N#newEntry(Object, Object)}
*/
@Deprecated
public static Map.Entry newEntry(final K key, final V value) {
return N.newEntry(key, value);
}
/**
* Creates a new immutable entry with the provided key and value.
*
* This method generates a new immutable entry (key-value pair) using the provided key and value.
* The created entry is immutable, meaning that its key and value cannot be changed after creation.
*
* @param key The key of the new entry.
* @param value The value of the new entry.
* @return A new ImmutableEntry with the provided key and value.
* @deprecated replaced by {@link N#newImmutableEntry(Object, Object)}
*/
@Deprecated
public static ImmutableEntry newImmutableEntry(final K key, final V value) {
return N.newImmutableEntry(key, value);
}
/**
* New target map.
*
* @param m
* @return
*/
@SuppressWarnings("rawtypes")
static Map newTargetMap(final Map, ?> m) {
return newTargetMap(m, m == null ? 0 : m.size());
}
/**
* New target map.
*
* @param m
* @param size
* @return
*/
@SuppressWarnings("rawtypes")
static Map newTargetMap(final Map, ?> m, final int size) {
if (m == null) {
return size == 0 ? new HashMap<>() : new HashMap<>(size);
}
if (m instanceof SortedMap) {
return new TreeMap<>(((SortedMap) m).comparator());
}
return N.newMap(m.getClass(), size);
}
/**
* New ordering map.
*
* @param m
* @return
*/
@SuppressWarnings("rawtypes")
static Map newOrderingMap(final Map, ?> m) {
if (m == null) {
return new HashMap<>();
}
if (m instanceof SortedMap) {
return new LinkedHashMap<>();
}
return N.newMap(m.getClass(), m.size());
}
/**
* Creates a Map by zipping together two Iterables, one containing keys and the other containing values.
* The Iterables should be of the same length. If they are not, the resulting Map will have the size of the smaller Iterable.
* The keys and values are associated in the order in which they are provided (i.e., the first key is associated with the first value, and so on).
*
* @param The type of keys in the resulting Map.
* @param The type of values in the resulting Map.
* @param keys An Iterable of keys for the resulting Map.
* @param values An Iterable of values for the resulting Map.
* @return A Map where each key from the keys Iterable is associated with the corresponding value from the values Iterable.
*/
public static Map zip(final Iterable extends K> keys, final Iterable extends V> values) {
if (N.isEmpty(keys) || N.isEmpty(values)) {
return new HashMap<>();
}
final Iterator extends K> keyIter = keys.iterator();
final Iterator extends V> valueIter = values.iterator();
final int minLen = N.min(keys instanceof Collection ? ((Collection) keys).size() : 0,
values instanceof Collection ? ((Collection) values).size() : 0);
final Map result = N.newHashMap(minLen);
for (int i = 0; i < minLen; i++) {
result.put(keyIter.next(), valueIter.next());
}
return result;
}
/**
* Creates a Map by zipping together two Iterables, one containing keys and the other containing values.
* The Iterables should be of the same length. If they are not, the resulting Map will have the size of the smaller Iterable.
* The keys and values are associated in the order in which they are provided (i.e., the first key is associated with the first value, and so on).
*
* @param The type of keys in the resulting Map.
* @param The type of values in the resulting Map.
* @param The type of the resulting Map.
* @param keys An Iterable of keys for the resulting Map.
* @param values An Iterable of values for the resulting Map.
* @param mapSupplier A function that generates a new Map instance.
* @return A Map where each key from the keys Iterable is associated with the corresponding value from the values Iterable.
*/
public static > M zip(final Iterable extends K> keys, final Iterable extends V> values,
final IntFunction extends M> mapSupplier) {
if (N.isEmpty(keys) || N.isEmpty(values)) {
return mapSupplier.apply(0);
}
final Iterator extends K> keyIter = keys.iterator();
final Iterator extends V> valueIter = values.iterator();
final int minLen = N.min(keys instanceof Collection ? ((Collection) keys).size() : 0,
values instanceof Collection ? ((Collection) values).size() : 0);
final M result = mapSupplier.apply(minLen);
for (int i = 0; i < minLen; i++) {
result.put(keyIter.next(), valueIter.next());
}
return result;
}
/**
* Creates a Map by zipping together two Iterables, one containing keys and the other containing values.
* The Iterables should be of the same length. If they are not, the resulting Map will have the size of the smaller Iterable.
* The keys and values are associated in the order in which they are provided (i.e., the first key is associated with the first value, and so on).
* If there are duplicate keys, the merge function is used to resolve the conflict.
*
* @param The type of keys in the resulting Map.
* @param The type of values in the resulting Map.
* @param The type of the resulting Map.
* @param keys An Iterable of keys for the resulting Map.
* @param values An Iterable of values for the resulting Map.
* @param mergeFunction A function used to resolve conflicts if there are duplicate keys.
* @param mapSupplier A function that generates a new Map instance.
* @return A Map where each key from the keys Iterable is associated with the corresponding value from the values Iterable.
*/
public static > M zip(final Iterable extends K> keys, final Iterable extends V> values,
final BiFunction super V, ? super V, ? extends V> mergeFunction, final IntFunction extends M> mapSupplier) {
if (N.isEmpty(keys) || N.isEmpty(values)) {
return mapSupplier.apply(0);
}
final Iterator extends K> keyIter = keys.iterator();
final Iterator extends V> valueIter = values.iterator();
final int minLen = N.min(keys instanceof Collection ? ((Collection) keys).size() : 0,
values instanceof Collection ? ((Collection) values).size() : 0);
final M result = mapSupplier.apply(minLen);
for (int i = 0; i < minLen; i++) {
result.merge(keyIter.next(), valueIter.next(), mergeFunction);
}
return result;
}
/**
* Creates a Map by zipping together two Iterables, one containing keys and the other containing values.
* The Iterables should be of the same length. If they are not, the resulting Map will have the size of the longer Iterable.
* The keys and values are associated in the order in which they are provided (i.e., the first key is associated with the first value, and so on).
* If a key or value is not present in the Iterable, the corresponding default value is used.
*
* @param The type of keys in the resulting Map.
* @param The type of values in the resulting Map.
* @param keys An Iterable of keys for the resulting Map.
* @param values An Iterable of values for the resulting Map.
* @param defaultForKey The default key to be used if the keys Iterable is shorter than the values Iterable.
* @return A Map where each key from the keys Iterable is associated with the corresponding value from the values Iterable.
*/
public static Map zip(final Iterable extends K> keys, final Iterable extends V> values, final K defaultForKey, final V defaultForValue) {
return zip(keys, values, defaultForKey, defaultForValue, Fn.selectFirst(), Factory.ofMap());
}
/**
* Creates a Map by zipping together two Iterables, one containing keys and the other containing values.
* The Iterables should be of the same length. If they are not, the resulting Map will have the size of the longer Iterable.
* The keys and values are associated in the order in which they are provided (i.e., the first key is associated with the first value, and so on).
* If there are duplicate keys, the merge function is used to resolve the conflict.
* If a key or value is not present in the Iterable, the corresponding default value is used.
*
* @param The type of keys in the resulting Map.
* @param The type of values in the resulting Map.
* @param The type of the resulting Map.
* @param keys An Iterable of keys for the resulting Map.
* @param values An Iterable of values for the resulting Map.
* @param defaultForKey The default key to be used if the keys Iterable is shorter than the values Iterable.
* @param defaultForValue The default value to be used if the values Iterable is shorter than the keys Iterable.
* @param mergeFunction A function used to resolve conflicts if there are duplicate keys.
* @param mapSupplier A function that generates a new Map instance.
* @return A Map where each key from the keys Iterable is associated with the corresponding value from the values Iterable.
*/
public static > M zip(final Iterable extends K> keys, final Iterable extends V> values, final K defaultForKey,
final V defaultForValue, final BiFunction super V, ? super V, ? extends V> mergeFunction, final IntFunction extends M> mapSupplier) {
if (N.isEmpty(keys) || N.isEmpty(values)) {
return mapSupplier.apply(0);
}
final Iterator extends K> keyIter = keys.iterator();
final Iterator extends V> valueIter = values.iterator();
final int maxLen = N.max(keys instanceof Collection ? ((Collection) keys).size() : 0,
values instanceof Collection ? ((Collection) values).size() : 0);
final M result = mapSupplier.apply(maxLen);
while (keyIter.hasNext() && valueIter.hasNext()) {
result.merge(keyIter.next(), valueIter.next(), mergeFunction);
}
while (keyIter.hasNext()) {
result.merge(keyIter.next(), defaultForValue, mergeFunction);
}
while (valueIter.hasNext()) {
result.merge(defaultForKey, valueIter.next(), mergeFunction);
}
return result;
}
/**
* Returns a {@code Nullable} with the value to which the specified key is mapped,
* or an empty {@code Nullable} if the specified map is empty or contains no mapping for the key.
*
* @param the type of keys maintained by the map
* @param the type of mapped values
* @param map the map from which to retrieve the value
* @param key the key whose associated value is to be returned
* @return a {@code Nullable} with the value mapped by the specified key, or an empty {@code Nullable} if the map is empty or contains no value for the key
* @see #getOrDefaultIfAbsent(Map, Object, Object)
*/
public static Nullable get(final Map map, final K key) {
if (N.isEmpty(map)) {
return Nullable.empty();
}
final V val = map.get(key);
if (val != null || map.containsKey(key)) {
return Nullable.of(val);
} else {
return Nullable.empty();
}
}
// /**
// * Returns the value to which the specified key is mapped if the value not {@code null},
// * or {@code defaultForNull} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
// *
// * @param
// * @param
// * @param map
// * @param key
// * @param defaultForNull to return if the specified {@code map} doesn't contain the specified {@code key} or the mapped value is {@code null}.
// * @return
// * @throws IllegalArgumentException if the specified {@code defaultForNull} is {@code null}
// * @deprecated Use {@link #getOrDefaultIfAbsent(Map, Object, Object)} instead
// */
// @Deprecated
// public static V getOrDefaultIfNull(final Map map, final K key, final V defaultForNull) throws IllegalArgumentException {
// return getOrDefaultIfAbsent(map, key, defaultForNull);
// }
/**
* Returns a {@code Nullable} with the value to which the specified {@code key/k2} is mapped,
* or an empty {@code Nullable} if the specified map is empty or contains no mapping for the key.
*
* @param the type of the outer map's keys
* @param the type of the inner map's keys
* @param the type of the inner map's values
* @param map the map from which to retrieve the value
* @param key the key whose associated map is to be returned
* @param k2 the key whose associated value in the inner map is to be returned
* @return a {@code Nullable} with the value mapped by the specified key and k2, or an empty {@code Nullable} if the map is empty or contains no value for the key
* @see #getOrDefaultIfAbsent(Map, Object, Object, Object)
*/
public static Nullable get(final Map> map, final K key, final K2 k2) {
if (N.isEmpty(map)) {
return Nullable.empty();
}
final Map m2 = map.get(key);
if (N.notEmpty(m2)) {
final V2 v2 = m2.get(k2);
if (v2 != null || m2.containsKey(k2)) {
return Nullable.of(v2);
}
}
return Nullable.empty();
}
/**
* Returns the value to which the specified key is mapped if the value is not {@code null},
* or {@code defaultValue} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
*
* @param the type of keys maintained by the map
* @param the type of mapped values
* @param map the map from which to retrieve the value
* @param key the key whose associated value is to be returned
* @param defaultValue the default value to return if the map is empty, contains no value for the key, or the value is null
* @return the value mapped by the specified key, or {@code defaultValue} if the map is empty, contains no value for the key, or the value is null
* @throws IllegalArgumentException if specified {@code defaultValue} is null
* @see #get(Map, Object)
* @see #getNonNull(Map, Object, Object)
*/
public static V getOrDefaultIfAbsent(final Map map, final K key, final V defaultValue) {
N.checkArgNotNull(defaultValue, cs.defaultValue);
if (N.isEmpty(map)) {
return defaultValue;
}
final V val = map.get(key);
// if (val != null || map.containsKey(key)) {
if (val == null) {
return defaultValue;
} else {
return val;
}
}
// /**
// * Returns the value to which the specified key is mapped if the value not {@code null},
// * or {@code defaultForNull} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
// *
// * @param
// * @param
// * @param map
// * @param key
// * @param defaultForNull to return if the specified {@code map} doesn't contain the specified {@code key} or the mapped value is {@code null}.
// * @return
// * @throws IllegalArgumentException if the specified {@code defaultForNull} is {@code null}
// * @deprecated Use {@link #getOrDefaultIfAbsent(Map, Object, Object)} instead
// */
// @Deprecated
// public static V getOrDefaultIfNull(final Map map, final K key, final V defaultForNull) throws IllegalArgumentException {
// return getOrDefaultIfAbsent(map, key, defaultForNull);
// }
/**
* Returns the value to which the specified key and k2 are mapped if the value is not {@code null},
* or {@code defaultValue} if the specified map is empty or contains no value for the key and k2 or the mapping value is {@code null}.
*
* @param the type of the outer map's keys
* @param the type of the inner map's keys
* @param the type of the inner map's values
* @param map the map from which to retrieve the value
* @param key the key whose associated map is to be returned
* @param k2 the key whose associated value in the inner map is to be returned
* @param defaultValue the default value to return if the map is empty, contains no value for the key and k2, or the value is null
* @return the value mapped by the specified key and k2, or {@code defaultValue} if the map is empty, contains no value for the key and k2, or the value is null
* @throws IllegalArgumentException if specified {@code defaultValue} is null
* @see #get(Map, Object, Object)
*/
public static V2 getOrDefaultIfAbsent(final Map> map, final K key, final K2 k2, final V2 defaultValue) {
N.checkArgNotNull(defaultValue, cs.defaultValue);
if (N.isEmpty(map)) {
return defaultValue;
}
final Map m2 = map.get(key);
if (N.notEmpty(m2)) {
final V2 v2 = m2.get(k2);
if (v2 != null) {
return v2;
}
}
return defaultValue;
}
// /**
// * Returns the value to which the specified key is mapped, or
// * an empty immutable/unmodifiable {@code List} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
// *
// * @param the key type
// * @param
// * @param the value type
// * @param map
// * @param key
// * @return
// * @deprecated Use {@link #getOrEmptyListIfAbsent(Map,K)} instead
// */
// @Deprecated
// public static > List getOrEmptyListIfNull(final Map map, final K key) {
// return getOrEmptyListIfAbsent(map, key);
// }
/**
* Returns the value to which the specified key is mapped, or
* an empty immutable/unmodifiable {@code List} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
*
*
* Absent -> key is not found in the specified map or found with {@code null} value.
*
* @param the type of keys maintained by the map
* @param the type of elements in the list
* @param the type of list values maintained by the map
* @param map the map from which to retrieve the value
* @param key the key whose associated value is to be returned
* @return the value mapped by the specified key, or an empty immutable/unmodifiable {@code List} if the map is empty, contains no value for the key, or the value is null
* @see N#emptyList()
*/
public static > List getOrEmptyListIfAbsent(final Map map, final K key) {
if (N.isEmpty(map)) {
return N.emptyList();
}
final V val = map.get(key);
if (val == null) {
return N.emptyList();
}
return val;
}
// /**
// * Returns the value to which the specified key is mapped, or
// * an empty immutable/unmodifiable {@code Set} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
// *
// * @param the key type
// * @param
// * @param the value type
// * @param map
// * @param key
// * @return
// * @deprecated Use {@link #getOrEmptySetIfAbsent(Map,K)} instead
// */
// @Deprecated
// public static > Set getOrEmptySetIfNull(final Map map, final K key) {
// return getOrEmptySetIfAbsent(map, key);
// }
/**
* Returns the value to which the specified key is mapped, or
* an empty immutable/unmodifiable {@code Set} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
*
*
* Absent -> key is not found in the specified map or found with {@code null} value.
*
* @param the type of keys maintained by the map
* @param the type of elements in the set
* @param the type of set values maintained by the map
* @param map the map from which to retrieve the value
* @param key the key whose associated value is to be returned
* @return the value mapped by the specified key, or an empty immutable/unmodifiable {@code Set} if the map is empty, contains no value for the key, or the value is null
* @see N#emptySet()
*/
public static > Set getOrEmptySetIfAbsent(final Map map, final K key) {
if (N.isEmpty(map)) {
return N.emptySet();
}
final V val = map.get(key);
if (val == null) {
return N.emptySet();
}
return val;
}
// /**
// * Returns the value to which the specified key is mapped, or
// * an empty immutable/unmodifiable {@code Map} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
// *
// * @param the key type
// * @param the key type of value map
// * @param the value type of value map
// * @param the value type
// * @param map
// * @param key
// * @return
// * @deprecated Use {@link #getOrEmptyMapIfAbsent(Map,K)} instead
// */
// @Deprecated
// public static > Map getOrEmptyMapIfNull(final Map map, final K key) {
// return getOrEmptyMapIfAbsent(map, key);
// }
/**
* Returns the value to which the specified key is mapped, or
* an empty immutable/unmodifiable {@code Map} if the specified map is empty or contains no value for the key or the mapping value is {@code null}.
*
*
* Absent -> key is not found in the specified map or found with {@code null} value.
*
* @param the type of keys maintained by the outer map
* @param the type of keys maintained by the inner map
* @param the type of values maintained by the inner map
* @param the type of map values maintained by the outer map
* @param map the map from which to retrieve the value
* @param key the key whose associated value is to be returned
* @return the value mapped by the specified key, or an empty immutable/unmodifiable {@code Map} if the map is empty, contains no value for the key, or the value is null
* @see N#emptyMap()
*/
public static > Map getOrEmptyMapIfAbsent(final Map map, final K key) {
if (N.isEmpty(map)) {
return N.emptyMap();
}
final V val = map.get(key);
if (val == null) {
return N.emptyMap();
}
return val;
}
/**
* Returns an empty {@code OptionalBoolean} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalBoolean} with the value mapped by the specified {@code key}.
* If the mapped value is not Boolean type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalBoolean getBoolean(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalBoolean.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalBoolean.empty();
} else if (val instanceof Boolean) {
return OptionalBoolean.of((Boolean) val);
} else {
return OptionalBoolean.of(Strings.parseBoolean(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Boolean type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static boolean getBoolean(final Map super K, ?> map, final K key, final boolean defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Boolean) {
return (Boolean) val;
} else {
return Strings.parseBoolean(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalChar} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalChar} with the value mapped by the specified {@code key}.
* If the mapped value is not Character type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalChar getChar(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalChar.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalChar.empty();
} else if (val instanceof Character) {
return OptionalChar.of(((Character) val));
} else {
return OptionalChar.of(Strings.parseChar(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Character type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static char getChar(final Map super K, ?> map, final K key, final char defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Character) {
return (Character) val;
} else {
return Strings.parseChar(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalByte} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalByte} with the value mapped by the specified {@code key}.
* If the mapped value is not Byte/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalByte getByte(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalByte.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalByte.empty();
} else if (val instanceof Number) {
return OptionalByte.of(((Number) val).byteValue());
} else {
return OptionalByte.of(Numbers.toByte(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Byte/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static byte getByte(final Map super K, ?> map, final K key, final byte defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Number) {
return ((Number) val).byteValue();
} else {
return Numbers.toByte(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalShort} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalShort} with the value mapped by the specified {@code key}.
* If the mapped value is not Short/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalShort getShort(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalShort.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalShort.empty();
} else if (val instanceof Number) {
return OptionalShort.of(((Number) val).shortValue());
} else {
return OptionalShort.of(Numbers.toShort(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Short/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static short getShort(final Map super K, ?> map, final K key, final short defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Number) {
return ((Number) val).shortValue();
} else {
return Numbers.toShort(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalInt} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalInt} with the value mapped by the specified {@code key}.
* If the mapped value is not Integer/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalInt getInt(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalInt.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalInt.empty();
} else if (val instanceof Number) {
return OptionalInt.of(((Number) val).intValue());
} else {
return OptionalInt.of(Numbers.toInt(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Integer/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static int getInt(final Map super K, ?> map, final K key, final int defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Number) {
return ((Number) val).intValue();
} else {
return Numbers.toInt(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalLong} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalLong} with the value mapped by the specified {@code key}.
* If the mapped value is not Long/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalLong getLong(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalLong.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalLong.empty();
} else if (val instanceof Number) {
return OptionalLong.of(((Number) val).longValue());
} else {
return OptionalLong.of(Numbers.toLong(N.toString(val)));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Long/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static long getLong(final Map super K, ?> map, final K key, final long defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else if (val instanceof Number) {
return ((Number) val).longValue();
} else {
return Numbers.toLong(N.toString(val));
}
}
/**
* Returns an empty {@code OptionalFloat} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalFloat} with the value mapped by the specified {@code key}.
* If the mapped value is not Float/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static OptionalFloat getFloat(final Map super K, ?> map, final K key) {
if (N.isEmpty(map)) {
return OptionalFloat.empty();
}
final Object val = map.get(key);
if (val == null) {
return OptionalFloat.empty();
} else {
return OptionalFloat.of(Numbers.toFloat(val));
}
}
/**
* Returns the specified {@code defaultForNull} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns the value mapped by the specified {@code key}.
* If the mapped value is not Float/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @param defaultForNull
* @return
*/
public static float getFloat(final Map super K, ?> map, final K key, final float defaultForNull) {
if (N.isEmpty(map)) {
return defaultForNull;
}
final Object val = map.get(key);
if (val == null) {
return defaultForNull;
} else {
return Numbers.toFloat(val);
}
}
/**
* Returns an empty {@code OptionalDouble} if the specified {@code map} is empty, or no value found by the specified {@code key}, or the mapping value is {@code null}.
* Otherwise returns an {@code OptionalDouble} with the value mapped by the specified {@code key}.
* If the mapped value is not Double/Number type, underline conversion will be executed.
*
* @param
* @param map
* @param key
* @return
*/
public static