Best way to create an empty map in Java - java

I need to create an empty map.
if (fileParameters == null)
fileParameters = (HashMap<String, String>) Collections.EMPTY_MAP;
The problem is that the above code produces this warning:
Type safety: Unchecked cast from Map to HashMap
What is the best way to create this empty map?

1) If the Map can be immutable:
Collections.emptyMap()
// or, in some cases:
Collections.<String, String>emptyMap()
You'll have to use the latter sometimes when the compiler cannot automatically figure out what kind of Map is needed (this is called type inference). For example, consider a method declared like this:
public void foobar(Map<String, String> map){ ... }
When passing the empty Map directly to it, you have to be explicit about the type:
foobar(Collections.emptyMap()); // doesn't compile
foobar(Collections.<String, String>emptyMap()); // works fine
2) If you need to be able to modify the Map, then for example:
new HashMap<String, String>()
(as tehblanx pointed out)
Addendum: If your project uses Guava, you have the following alternatives:
1) Immutable map:
ImmutableMap.of()
// or:
ImmutableMap.<String, String>of()
Granted, no big benefits here compared to Collections.emptyMap(). From the Javadoc:
This map behaves and performs comparably to Collections.emptyMap(),
and is preferable mainly for consistency and maintainability of your
code.
2) Map that you can modify:
Maps.newHashMap()
// or:
Maps.<String, String>newHashMap()
Maps contains similar factory methods for instantiating other types of maps as well, such as TreeMap or LinkedHashMap.
Update (2018): On Java 9 or newer, the shortest code for creating an immutable empty map is:
Map.of()
...using the new convenience factory methods from JEP 269. 😎

Collections.emptyMap()

The emptyMap method of the Collections class.

If you need an instance of HashMap, the best way is:
fileParameters = new HashMap<String,String>();
Since Map is an interface, you need to pick some class that instantiates it if you want to create an empty instance. HashMap seems as good as any other - so just use that.

Either Collections.emptyMap(), or if type inference doesn't work in your case,
Collections.<String, String>emptyMap()

Since in many cases an empty map is used for null-safe design, you can utilize the nullToEmpty utility method:
class MapUtils {
static <K,V> Map<K,V> nullToEmpty(Map<K,V> map) {
if (map != null) {
return map;
} else {
return Collections.<K,V>emptyMap(); // or guava ImmutableMap.of()
}
}
}
Similarly for sets:
class SetUtils {
static <T> Set<T> nullToEmpty(Set<T> set) {
if (set != null) {
return set;
} else {
return Collections.<T>emptySet();
}
}
}
and lists:
class ListUtils {
static <T> List<T> nullToEmpty(List<T> list) {
if (list != null) {
return list;
} else {
return Collections.<T>emptyList();
}
}
}

What about :
Map<String, String> s = Collections.emptyMap();

You can use:
Collections<String, String>.emptyMap();

Related

Java Map - log message when key is not found in getOrDefault

I have a Map<String, List<SomeClass>> someMap and I'm retrieving the value based on someKey and for each element of the list of SomeClass I'm performing other operations.
someMap.getOrDefault(someKey, new ArrayList<>()).forEach(...)
I also want to be able to log messages when I don't find someKey. How would I be able to achieve it optimally? Is there any other function/way to achieve this behavior?
Map<String, List<String>> map = new HashMap<>();
List<String> l = new ArrayList<>();
l.add("b");
map.put("a", l);
Yes, you can do it in a single statement. Use .compute().
map.compute("a", (k, v) -> {
if (v == null) {
System.out.println("Key Not Found");
return new ArrayList<>();
}
return v;
}).forEach(System.out::println);
There's also computeIfAbsent() which will only compute the lambda if the key is not present.
Note, from the documentation:
Attempts to compute a mapping for the specified key and its current
mapped value (or null if there is no current mapping).
This will add the key which was not found in your map.
If you want to remove those keys later, then simply add those keys to a list inside the if and remove them in one statement like this:
map.keySet().removeAll(listToRemove);
You can create a function to do that. For example, I created a function which will get the value from the map, return it if it is not null, or an empty list otherwise. Before returning the empty list, you can run a Runnable action. The main benefit of that is that you can do more than just logging there.
#Slf4j
public class Main {
public static Collection<String> retrieveOrRun(Map<String, Collection<String>> map, String key, Runnable runnable) {
final Collection<String> strings = map.get(key);
if (strings == null) {
runnable.run();
return Collections.emptyList();
} else {
return strings;
}
}
public static void main(String[] args) {
Map<String, Collection<String>> map = new HashMap<>();
Collection<String> strings = retrieveOrRun(map, "hello", () -> log.warn("Could not find a value for the key : {}", "hello"));
}
}
I think you have two choices:
Either you use a wrapper method, doing the actual call (getOrDefault, etc) and handling missing keys.
public static <K,V> V getOrDefault(Map<K,V> map, K key, V defaultValue) {
V value = map.get(key);
if (value == null) {
logMissingValue(key);
return defaultValue;
}
return value;
}
Or you create new implementation of Map doing just that, with a delegation to method that should be delegated (I won't do here in this example, but Eclipse work pretty well: Alt + Shift + S > Create delegate methods):
class LoggerMap<K,V> implements Map<K,V> {
private final Map<K,V> internal;
public LoggerMap(Map<K,V> internal) {
this.internal = Objects.requireNonNull(internal, "internal");
}
#Override
public V getOrDefault(K key, V defaultValue) {
... if not found logMissingValue(key); ...
}
}
Now about which is optimal, that depends on your needs: if you know you will always use the wrapper method, then your missing keys will always be logged. Creating a new map implementation would be overkill.
If your need is to log absolutely all missing keys - even if foreign code (for example, some API taking a map as a parameter), then your best choice is a map implementation:
In terms of performance, I don't think you should worry about delegation: I did not test it using a benchmark, but the JVM should be able to optimize that.
There are other parts where a key might return a missing value (eg: remove, get, ...), using such an implementation will allow you to easily trace those as well.

How to get the first key value from map using JAVA 8?

As for now I am doing :
Map<Item, Boolean> processedItem = processedItemMap.get(i);
Map.Entry<Item, Boolean> entrySet = getNextPosition(processedItem);
Item key = entrySet.getKey();
Boolean value = entrySet.getValue();
public static Map.Entry<Item, Boolean> getNextPosition(Map<Item, Boolean> processedItem) {
return processedItem.entrySet().iterator().next();
}
Is there any cleaner way to do this with java8 ?
I see two problems with your method:
it will throw an exception if the map is empty
a HashMap, for example, has no order - so your method is really more of a getAny() than a getNext().
With a stream you could use either:
//if order is important, e.g. with a TreeMap/LinkedHashMap
map.entrySet().stream().findFirst();
//if order is not important or with unordered maps (HashMap...)
map.entrySet().stream().findAny();
which returns an Optional.
Seems like you need findFirst here
Optional<Map.Entry<Item, Boolean>> firstEntry =
processedItem.entrySet().stream().findFirst();
Obviously a HashMap has no order, so findFirst might return a different result on different calls. Probably a more suitable method would be findAny for your case.

Java HashMap in methods

Is it possible to have a method requiring a HashMap and be able to provide any HashMap with Strings as keys? Some kind of generic data Type to put instead of 'Value'?
public void example(HashMap<String, Value> hashMap) {
//Stuff
}
example(new HashMap<String, Integer>);
HashMap<String, String> exampleMap = new HashMap<>();
example(exampleMap);
Alternatively, is it possible to check the key/value type of the map, other than looping through all the keys/value and check instanceof (without stopping it with return)?
public Boolean example(HashMap<String, Value> hashMap) {
for (Value value : hashMap.values())) {
if (value instanceof String) {
return true; //<- Unwanted
}
}
}
EDIT:
Let me explain my problem a bit further. I have a method:
public static Object getEIC(HashMap<String, Object> map, String key) {
for (String keys : map.keySet()) {
if (keys.equalsIgnoreCase(key)) {
return map.get(keys);
}
}
return null;
}
EIC stands for equalsIgnoreCase. So I need some generic return Type as well. Thanks for the answers so far, and thanks on forehand for the answers on this!
You could do:
HashMap<String, Object>
But that's terrible though because then you end up doing instanceof all the time. What you really need to do is understand what the key problem is and then think of inheritance. Can you define an interface that all your value objects would implement? For instance GeometricShape which could be implemented by Rectangle and Circle.
Also, you can define a HashMap as follows:
HashMap<String, ? extends SomeClass>
And as others pointed out, it's best to use the interface Map rather than a specific implementation e.g. HashMap.
Lastly, as I pointed out in a comment, it seems you are just trying to implement a Map<key, value> where you want to have case-insensitive keys. If so have a look at www.stackoverflow.com/questions/8236945/
The answer is to use a CaseInsensitiveMap. Thanks, everyone, for helping me and especially David Brossard for suggesting this.
You can implement the static method you are looking for using generics:
public static <V> V getEIC(Map<String, V> map, String key) {
for (String k : map.keySet()) {
if (k.equalsIgnoreCase(key)) {
return map.get(key);
}
}
return null;
}
however, you may wish to consider an enhanced Map Is there a good way to have a Map<String, ?> get and put ignoring case?
Note, however, that there is a subtle difference between this solution and using case-less equals - an ordinary Map<String,V> could hold a value for "Key" and "key" while a case-less Map would not. This method would arbitrarily choose one of them while a case-less Map would choose the most recent addition.
Yes, but requiring Map<String, Value> is better. If you don't care what value is ask for Map<String, ?>. If you do but don't yet know what it will be, use Map<String, ? extends T>
Requiring HashMap is programing to an implementation rather than an interface. There is rarely a good reason to do that.
And no. If you don't trust whoever built the map and want to be sure the map contains only the types it's supposed to contain you have to loop and check each one. However, you can abstract that away in a method that will check for you so you don't have to look at it.
public class CheckedCast
{
public static <K,V> Map<K,V> mapOf(Class<? extends K> classK,
Class<? extends V> classV,
Map<?,?> m)
{
for (Map.Entry<?, ?> e: m.entrySet())
{
classK.cast( e.getKey() );
classV.cast( e.getValue() );
}
#SuppressWarnings("unchecked")
Map<K,V> result = (Map<K,V>) m;
return result;
}
}

Java Map with multiple keys

I need to create a map, with 3 columns: 2 keys, and 1 value. So each value will contain 2 keys of different classtypes, and can be fetched by using either one. But my problem is that HashMap/Map supports only 1 key, and 1 value. Is there a way to create something like Map<Key1, Key2, Value> instead of Map<Key, Value>? so Value can be fetched by either using its Key1 or Key2.
I apologize if it is a duplicate or a bad question, but I couldn't find a similar one on Stack Overflow.
P.S: I don't want to create 2 maps: Map<Key1, Value> and Map<Key2, Value> nor creating nested maps I am looking for a multikey table, just one like above.
You're probably going to have to write a custom implementation of a map-like class to implement this. I agree with #William Price above, the easiest implementation will be to simply encapsulate two Map instances. Be careful using the Map interface, as they rely on equals() and hashCode() for key identity, which you intend to break in your contract.
Write class with your requirements by yourself:
import java.util.HashMap;
import java.util.Map;
public class MMap<Key, OtherKey, Value> {
private final Map<Key, Value> map = new HashMap<>();
private final Map<OtherKey, Value> otherMap = new HashMap<>();
public void put(Key key, OtherKey otherKey, Value value) {
if (key != null) { // you can change this, if you want accept null.
map.put(key, value);
}
if (otherKey != null) {
otherMap.put(otherKey, value);
}
}
public Value get(Key key, OtherKey otherKey) {
if (map.containsKey(key) && otherMap.containsKey(otherKey)) {
if (map.get(key).equals(otherMap.get(otherKey))) {
return map.get(key);
} else {
throw new AssertionError("Collision. Implement your logic.");
}
} else if (map.containsKey(key)) {
return map.get(key);
} else if (otherMap.containsKey(otherKey)) {
return otherMap.get(otherKey);
} else {
return null; // or some optional.
}
}
public Value getByKey(Key key) {
return get(key, null);
}
public Value getByOtherKey(OtherKey otherKey) {
return get(null, otherKey);
}
}
Just store the value twice:
Map<Object, Value> map = new HashMap<>();
map.put(key1, someValue);
map.put(key2, someValue);
The thing is, it doesn't really matter what type the key is, so use a generic bound that allows both key types - Object is fine.
Note that the parameter type of Map#get() method is just Object anyway, so from a look-up perspective there's no value in having separate maps (the type of the key is only relevant for put()).
Have you looked into Apache Commons Collection multi map interface?
https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/MultiMap.html
Take a look at guava's Table collection that can be used in your context
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Table.html
Table<String,String,String> ==> Map<String,Map<String,String>>

Java: how to convert a List<?> to a Map<String,?> [duplicate]

This question already has answers here:
How to convert List to Map?
(20 answers)
Closed 7 years ago.
I would like to find a way to take the object specific routine below and abstract it into a method that you can pass a class, list, and fieldname to get back a Map.
If I could get a general pointer on the pattern used or , etc that could get me started in the right direction.
Map<String,Role> mapped_roles = new HashMap<String,Role>();
List<Role> p_roles = (List<Role>) c.list();
for (Role el : p_roles) {
mapped_roles.put(el.getName(), el);
}
to this? (Pseudo code)
Map<String,?> MapMe(Class clz, Collection list, String methodName)
Map<String,?> map = new HashMap<String,?>();
for (clz el : list) {
map.put(el.methodName(), el);
}
is it possible?
Using Guava (formerly Google Collections):
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, Functions.toStringFunction());
Or, if you want to supply your own method that makes a String out of the object:
Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
public String apply(Role from) {
return from.getName(); // or something else
}});
Here's what I would do. I am not entirely sure if I am handling generics right, but oh well:
public <T> Map<String, T> mapMe(Collection<T> list) {
Map<String, T> map = new HashMap<String, T>();
for (T el : list) {
map.put(el.toString(), el);
}
return map;
}
Just pass a Collection to it, and have your classes implement toString() to return the name. Polymorphism will take care of it.
Java 8 streams and method references make this so easy you don't need a helper method for it.
Map<String, Foo> map = listOfFoos.stream()
.collect(Collectors.toMap(Foo::getName, Function.identity()));
If there may be duplicate keys, you can aggregate the values with the toMap overload that takes a value merge function, or you can use groupingBy to collect into a list:
//taken right from the Collectors javadoc
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
As shown above, none of this is specific to String -- you can create an index on any type.
If you have a lot of objects to process and/or your indexing function is expensive, you can go parallel by using Collection.parallelStream() or stream().parallel() (they do the same thing). In that case you might use toConcurrentMap or groupingByConcurrent, as they allow the stream implementation to just blast elements into a ConcurrentMap instead of making separate maps for each thread and then merging them.
If you don't want to commit to Foo::getName (or any specific method) at the call site, you can use a Function passed in by a caller, stored in a field, etc.. Whoever actually creates the Function can still take advantage of method reference or lambda syntax.
Avoid reflection like the plague.
Unfortunately, Java's syntax for this is verbose. (A recent JDK7 proposal would make it much more consise.)
interface ToString<T> {
String toString(T obj);
}
public static <T> Map<String,T> stringIndexOf(
Iterable<T> things,
ToString<T> toString
) {
Map<String,T> map = new HashMap<String,T>();
for (T thing : things) {
map.put(toString.toString(thing), thing);
}
return map;
}
Currently call as:
Map<String,Thing> map = stringIndexOf(
things,
new ToString<Thing>() { public String toString(Thing thing) {
return thing.getSomething();
}
);
In JDK7, it may be something like:
Map<String,Thing> map = stringIndexOf(
things,
{ thing -> thing.getSomething(); }
);
(Might need a yield in there.)
Using reflection and generics:
public static <T> Map<String, T> MapMe(Class<T> clz, Collection<T> list, String methodName)
throws Exception{
Map<String, T> map = new HashMap<String, T>();
Method method = clz.getMethod(methodName);
for (T el : list){
map.put((String)method.invoke(el), el);
}
return map;
}
In your documentation, make sure you mention that the return type of the method must be a String. Otherwise, it will throw a ClassCastException when it tries to cast the return value.
If you're sure that each object in the List will have a unique index, use Guava with Jorn's suggestion of Maps.uniqueIndex.
If, on the other hand, more than one object may have the same value for the index field (which, while not true for your specific example perhaps, is true in many use cases for this sort of thing), the more general way do this indexing is to use Multimaps.index(Iterable<V> values, Function<? super V,K> keyFunction) to create an ImmutableListMultimap<K,V> that maps each key to one or more matching values.
Here's an example that uses a custom Function that creates an index on a specific property of an object:
List<Foo> foos = ...
ImmutableListMultimap<String, Foo> index = Multimaps.index(foos,
new Function<Foo, String>() {
public String apply(Foo input) {
return input.getBar();
}
});
// iterate over all Foos that have "baz" as their Bar property
for (Foo foo : index.get("baz")) { ... }

Categories

Resources