I've tried the following line:
Map<Character, Color> map={new Character('r'):Color.red,new Character('b'):Color.black};
But Netbeans 7 rejects this, with the error message '{' expected, ';' expected.
I've set the Source/Binary format as 'JDK 7'and the platform to 'JDK 1.7', is there anything else I need to do?
Neither Java 7 nor Java 8 supports collection literals, as discussed in this question: Are Project Coin's collection enhancements going to be in JDK8?
You can use Google's Guava library if you need only immutable collections. ImmutableList, ImmutableSet and ImmutableMap have several overloaded factory methods or even builders that make creating collections easy:
List<Integer> list = ImmutableList.of(1, 1, 2, 3, 5, 8, 13, 21);
Set<String> set = ImmutableSet.of("foo", "bar", "baz", "batman");
Map<Integer, String> map = ImmutableMap.of(1, "one", 2, "two", 3, "three");
EDIT
Java 9 has added collection factory methods similar to those of Guava:
List.of(a, b, c);
Set.of(d, e, f, g);
Map.of(k1, v1, k2, v2)
Map.ofEntries(
entry(k1, v1),
entry(k2, v2),
entry(k3, v3),
// ...
entry(kn, vn)
);
You need to define a concrete map implementation, optionally combined with double brace initialization:
Map<Character, Color> map = new HashMap<Character, Color>() {{
put(new Character('r'), Color.red);
put(new Character('b'), Color.black );
}};
To expand a little on Thomas's answer... Map is an interface, and must be instantiated through one of the associated concrete implementations (HashMap, TreeMap, or LinkedHashMap). It is still good practice; however, to declare your reference variable as the interface implementation rather than the specific concrete, as it provides future flexibility.
Regarding the code snippet though, I think you do still need the Key-value pairs defined in the assignment side of the declaration. So, I would change:
Map<Character, Color> map = new HashMap<>() {{
to
Map<Character, Color> map = new HashMap<Character, Color>() {{
Related
I made up this function, it seems to make the work, but I wondered if there was an even cleaner solution.
public static <K, V> Map<V, List<K>> reverseMap(Map<K, List<V>> map) {
return map.entrySet().stream()
.flatMap(entry -> entry.getValue().stream().map(value -> new AbstractMap.SimpleEntry<>(value, entry.getKey())))
.collect(Collectors.groupingBy(
AbstractMap.SimpleEntry::getKey,
Collectors.mapping(AbstractMap.SimpleEntry::getValue, Collectors.toList())));
}
Bonus question: I have a java 8 constraint for this one, but how could later versions improve it? I assume I'd no longer have to use AbstractMap.SimpleEntry since Java 9 introduced the Map.entry(k, v) function.
Since you did not necessitate streams in your question, I'm going to advocate for a non-stream solution:
//example input
Map<Integer, List<Integer>> map = new HashMap<>();
map.put(1, Arrays.asList(11, 12, 13, 4));
map.put(2, Arrays.asList(21, 22, 23, 4));
map.put(3, Arrays.asList(31, 32, 33, 4));
//reversing
Map<Integer, List<Integer>> reversed = new HashMap<>();
map.forEach((key, list) -> {
list.forEach(value -> {
reversed.computeIfAbsent(value, k -> new ArrayList<>()).add(key);
});
});
//end result:
//{32=[3], 33=[3], 4=[1, 2, 3], 21=[2], 22=[2], 23=[2], 11=[1], 12=[1], 13=[1], 31=[3]}
In your stream-based solution, you will be creating new Entry objects per key-(list-value) pair in the map, which will then have to make additional entries when recombined into a map. By using a direct approach, you avoid this excess object creation and directly create the entries you need.
Note that not everything has to be a Stream, the "old" way of doing things can still be correct, if not better (in readability and performance terms) than a Stream implementation.
What would be a good practice to convert Map<Obj1, Collection<Obj2>> to Map<Obj2, Collection<Obj1>>?
I tried doing it with MultiMap.
Map<Obj1, Collection<Obj2>> originalMap = ...;
Multimap<Obj1, Obj2> multiMap = ArrayListMultimap.create();
originalMap.forEach(multiMap::putAll);
Map<Obj2, Collection<Obj1>> convertedMap = Multimaps.invertFrom(multiMap, ArrayListMultimap.create()).asMap();
Is there a better way to do this?
You can achieve the same with Java 8 Streams;
Map<Obj1, List<Obj2>> originalMap = ...
Map<Obj2, List<Obj1>> reversedMap = originalMap.entrySet().stream()
.flatMap(obj2s -> obj2s.getValue().stream()
.map(obj2 -> Map.entry(obj2, obj2s.getKey())))
.collect(
Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
)
);
The fltMap coverts Map<Obj1, List<Obj2>> into a tuple like <Obj2, Obj1>, then collect the result grouping by Obj2.
Your approach is correct, but could be even more straightforward if you used Multimap instead in the first place and
you don't need mutability,
you don't have nulls.
If that's the case, all you need is ImmutableMultimap#inverse():
ImmutableListMultimap<Integer, String> originalMultimap = ImmutableListMultimap.of(
1, "foo",
1, "bar",
2, "baz",
42, "foo"
);
ImmutableListMultimap<String, Integer> convertedMap = originalMultimap.inverse();
System.out.println(convertedMap); // {foo=[1, 42], bar=[1], baz=[2]}
I used ImmutableListMultimap instead of ImmutableMultimap because docs encourage to do so:
Warning: avoid direct usage of ImmutableMultimap as a type (as with Multimap itself). Prefer subtypes such as ImmutableSetMultimap or ImmutableListMultimap, which have well-defined equals(java.lang.Object) semantics, thus avoiding a common source of bugs and confusion.
The title question summarizes it nicely, but assume I am coding in Java and have a HashMap that looks something like this (it has a lot more entries obviously):
Map<String, Integer> myMap = new HashMap<>();
myMap.put{"a", 1}
myMap.put{"b", 2}
myMap.put{"c", 2}
myMap.put{"d", 3}
Now I don't like entries with the value of 2, so I want to remove them all as effectively as possible, leaving me only with the entries that have value 1 or 3.
It should look as if my map was instead made like this:
Map<String, Integer> myMap = new HashMap<>();
myMap.put{"a", 1}
myMap.put{"d", 3}
As if my 2-valued entries were never there at all!
What are my options for doing this in an effective way?
map.entrySet().removeIf(entry -> entry.getValue() == 2)
Using helper map
If you want to do it as effectively as possible you can create an inverted map:
HashMap<Integer, List<String>> affectedKeysMap = new HashMap<>();
You'll need to track all updates to both maps manually to keep them in sync.
This will allow you to find and remove affected keys in an effective way:
int valueToRemove = 2;
for(String affectedKey : affectedKeysMap.get(2)) {
map.remove(affectedKey);
}
affectedKeysMap.remove(valueToRemove);
Using single map
With a single HashMap all you can do is traverse the whole set of entries because HashMap doesn't support fast search by value.
This question already covers different approaches with a single map: Removing all items of a given value from a hashmap
Using something else
Another option is to look for a specialized collection class that supports bidirectional search and removal. Check out these discussions for possible leads:
Bidirectional multi-valued map in Java
Do we have a MultiBiMap ?
Using guava you could do it like this:
Integer valueToDrop = Integer.valueOf(2);
Predicate<Integer> predicate = Predicates.not(Predicates.equalTo(valueToDrop));
Map<String, Integer> filteredMap = Maps.filterValues(myMap, predicate);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
The arrival of Java 9 brings many new features to Java's Collections API, one of which being collection factory methods.
What are they and how can I implement them properly?
Note 1: To prevent the use of raw-types, I have opted to provide a generic type for each class that I mention below by using E, representing an element of a Collection<E>.
Note 2: This answer is subject to change; please edit this post if a typo has occurred.
What are collection factory methods?
A collection factory method in Java is a static method that provides a simple way of initializing an immutable Collection<E>.
Being immutable, no elements can be added to, removed from, or modified inside the Collection<E> after it is initialized.
With Java 9, collection factory methods are provided for the following interfaces: List<E>, Set<E>, and Map<K, V>
What do they improve?
Up until Java 9, there has been no simple, universal method to initialize a Collection<E> with initial elements/key-value entries. Previously, developers were required to initialize them as follows (assuming the generic types E, K, and V have been replaced with Integer):
List<Integer>
The following method is arguably the simplest to initialize a List<Integer> with initial elements, however the result is simply a view of a List<Integer>; we are unable to add to or remove from this List<Integer>, but we are still able to modify existing elements by using List#set.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
If we wanted our List<Integer> to be entirely mutable, then we would have to pass it to the constructor of an ArrayList<Integer>, for example:
List<Integer> mutableList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer>
A Set<Integer> required more code to initialize with initial elements than a List<Integer> does (seeing as a List<Integer> is required to initialize a Set<Integer> with initial elements), which can be seen below.
Set<Integer> mutableSet = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Map<Integer, Integer>
A Map<Integer, Integer> is arguably the most complicated to initialize with initial key-value entries; however, there are multiple ways to go about it.
One method was to first initialize an empty Map<Integer, Integer> and simply call Map#put to add key-value entries.
Another method was to use an anonymous class with two curly braces, which would still require Map#put to be called.
Why should I use them?
I argue that collection factory methods provide the developer with a concise method of initializing a List<E>, Set<E>, or Map<K, V> with initial elements/key-value entries, which can be seen by the examples below.
What is the proper syntax to use?
For simplicity, these examples will replace the generic types E, K, and V with Integer.
List<Integer>
List<Integer> list = List.of();
Initializes an empty, immutable List<Integer>.
List<Integer> list = List.of(1);
Initializes an immutable List<Integer> with one element.
List<Integer> list = List.of(1, 2);
Initializes an immutable List<Integer> with two elements.
List<Integer> list = List.of(1, 2, 3, 4, 5, ...);
Initializes an immutable List<Integer> with a variable amount of elements.
Set<Integer>
Set<Integer> set = Set.of();
Initializes an empty, immutable Set<Integer>.
Set<Integer> set = Set.of(1);
Initializes an immutable Set<Integer> with one element.
Set<Integer> set = Set.of(1, 2);
Initializes an immutable Set<Integer> with two elements.
Set<Integer> set = Set.of(1, 2, 3, 4, 5, ...);
Initializes an immutable Set<Integer> with a variable amount of elements.
Map<Integer, Integer>
Map<Integer, Integer> map = Map.of();
Initializes an empty, immutable Map<Integer, Integer>.
Map<Integer, Integer> map = Map.of(1, 2);
Initializes an immutable Map<Integer, Integer> with one key-value entry.
Note that the key is 1 and the value is 2.
Map<Integer, Integer> map = Map.of(1, 2, 3, 4);
Initializes an immutable Map<Integer, Integer> with two key-value entries.
Note that the keys are 1 and 3 and the values are 2 and 4.
Map<Integer, Integer> map = Map.ofEntries(Map.entry(1, 2), Map.entry(3, 4), ...);
Initializes an immutable Map<Integer, Integer> with a variable amount of key-value entries.
As you can see, this new method of initialization requires less code than its predecessors.
Can I use collection factory methods to create mutable objects?
The Collection<E> created by collection factory methods are inherently immutable, however we are able to pass them to a constructor of an implementation of the Collection<E> to produce a mutable version:
List<Integer>
List<Integer> mutableList = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Set<Integer>
Set<Integer> mutableSet = new HashSet<>(Set.of(1, 2, 3, 4, 5));
Map<Integer, Integer>
Map<Integer, Integer> mutableMap = new HashMap<>(Map.of(1, 2, 3, 4));
This question already has answers here:
How can I initialise a static Map?
(43 answers)
Closed 6 years ago.
I was just wondering if it is possible to define the contents of a Map Object on initialisation.
For example, an array can be created, as:
new String[] {“apples”, “bananas”, “pears”}
So, I was wondering if there is something similar we can do for maps.
You can, sort of, using this syntax trick:
Map<String,String> map = new HashMap<String,String>() {{
put("x", "y");
put("a", "b");
}};
Not very pleasant, though. This creates an anonymous subclass of HashMap, and populates it in the instance initializer.
If your Map is going to be immutable after creation and you don't mind adding a dependency, Guava offers some nice fluent syntax:
Map<K,V> aMap = ImmutableMap.<K,V>builder().put(key0, val0).put(key1,val1).build();
If you're feeling really exotic, Scala has syntax exactly like what you want and is interoperable with other Java code:
val aMap = Map("a"->0, "b"->1)
Note that the Scala compiler will infer the Map generic type is from String to Int, based on what you put in it, though you can explicitly specify it as well.
However, if this is just a one-off, I'd go with the initializer-based syntax. Both the Guava library and Scala language have a lot else to recommend them, but learning a whole new library/language might be overboard.
You can use initializer blocks:
class Foo {
//using static initializer block
static Map<String,String> m1 = new HashMap<String,String>();
static {
m1.put("x","y");
m1.put("a","b");
}
//using initializer block
Map<String,String> m2 = new HashMap<String,String>();
{
m2.put("x","y");
m2.put("a","b");
}
}
Something very hacky..can be improved, but this is just a direction:
Define a static helper to convert an object array to a map of this type:
public static<K,V> Map<K, V> fromArray(Object[] anObjArray){
int size = anObjArray.length;
Map<K, V> aMap = new HashMap<K, V>();
for (int i=0;i<=size/2;i=i+2){
K key = (K)anObjArray[i];
V value = (V)anObjArray[i+1];
aMap.put(key, value);
}
return aMap;
}
then you can create a map using this:
Map<Integer, String> aMap = MapUtils.<Integer, String>fromArray(new Object[]{1, "one", 2,"two"});
I would personally second Gauva builder suggestion from #Carl though :-)