Builder for Hashmap

builder for HashMap

Since Java 9 Map interface contains:

  • Map.of(k1,v1, k2,v2, ..)
  • Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..).

Limitations of those factory methods are that they:

  • can't hold nulls as keys and/or values (if you need to store nulls take a look at other answers)
  • produce immutable maps

If we need mutable map (like HashMap) we can use its copy-constructor and let it copy content of map created via Map.of(..)

Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );

ImmutableMap.Builder from a HashMap

Simply use putAll or am I missing something here? You cannot modify existing keys while building, but you can add more:

    Map<String, String> srcMap = Map.of("A", "a", "B", "b", "C", "c");

ImmutableMap<String, String> map = ImmutableMap.<String, String> builder()
.putAll(srcMap)
.put("D", "d")
.build();

map.forEach((k,v) -> System.out.printf ("[%s:%s]", k, v));

You could modify the srcMap itself before you invoke putAll if you want to override the existing values.

Also, if you have a HashMap that is ready to be converted to an ImmutableMap, you can skip the builder part and just use copyOf:

ImmutableMap<String, String> finalMap = ImmutableMap.copyOf(srcMap);

How to pass a HashMap to CriteriaBuilder and add to Predicates list

As always, writing the statement in (roughly) SQL helps:

SELECT ...
FROM Machine m
WHERE -- repeat for each map entry
EXISTS (SELECT ... FROM Tag t WHERE t.machine_id = m.id AND t.name = ?1 AND t.value = ?2)
AND EXISTS (SELECT ... FROM Tag t WHERE t.machine_id = m.id AND t.name = ?3 AND t.value = ?4)
...

If this suits your needs, it can be translated to criteria API roughly as follows (you will probably need to tweak it):

private Subquery<TagEntity> makeExistsSubquery(CriteriaQuery<MachineEntity> q, CriteriaBuilder cb, Map.Entry<String,String> e) {
Subquery<TagEntity> subquery = q.subquery(TagEntity.class);
Root<TagEntity> tagRoot = subquery.from(TagEntity.class);
subquery.where(cb.and(
cb.equal(tagRoot.get(TagEntity_.name), e.getKey()),
cb.equal(tagRoot.get(TagEntity_.value), e.getValue())
));
return subquery;
}

private void your_method() {
// assuming something like this exists:
CriteriaQuery<MachineEntity> query = criteriaBuilder.createQuery(MachineEntity.class);

// do this:
for (Map.Entry element : request.getTags().entrySet()) {
predicates.add(criteriaBuilder.exists(makeExistsSubquery(query, criteriaBuilder, element)));
}

...
}

I am not sure how efficient is this query going to be. But I hope this hints to a solution.

Additionally I am assuming you want machines that match ALL the given tags. If you want machines matching ANY of the given tags, the SQL query would be simpler:

SELECT ...
FROM Machine m JOIN Tag t ON t.machine_id = m.id
WHERE -- repeat for each map entry
t.name = ?1 AND t.value = ?2
OR t.name = ?3 AND t.value = ?4
...
Predicate tagsPredicate = criteriaBuilder.or( 
request.getTags().entrySet().stream()
.map(e -> criteriaBuilder.and(
criteriaBuilder.equal(join.get(TagEntity_.name), e.getKey()),
criteriaBuilder.equal(join.get(TagEntity_.value), e.getValue())
))
.collect(Collectors.toList())
.toArray(new Predicate[0])
);
// add the tagsPredicate to your where clause, if the user has actually defined tag criteria

Using List of HashMapString, dynamic to populate ListView Builder Flutter

Try:

 asyncSnapshot.data[index]["name"]

And

 asyncSnapshot.data[index]["email"]

How to use StringBuilder with Map

You can simply replace value + ", from anonymous\n" with value == null ? new StringBuilder(dto.getName()) : value.append(", from anonymous\n")).

Illustration:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class MyDto {
String type;
String name;

public MyDto(String type, String name) {
this.type = type;
this.name = name;
}

public String getType() {
return type;
}

public String getName() {
return name;
}
}

public class Main {
public static void main(String[] args) {
Map<String, StringBuilder> map = new HashMap<>();
List<MyDto> dtoCollection = new ArrayList<>();
for (MyDto dto : dtoCollection) {
map.compute(dto.getType(), (key, value) -> value == null ? new StringBuilder(dto.getName())
: value.append(", from anonymous\n"));
}
}
}

Am I missing something?

HashMap - Changing key value

emp = new StringBuilder("sss"); doesn't affect the entry that's already in the HashMap (the one created by the statement new StringBuilder("Stack");), since the HashMap contains its own reference to the StringBuilder instance that was originally referred by emp. It doesn't create a copy of the StringBuilder instance, it only keeps a copy of the reference.

On the other hand, with WeakHashMap, the presence of a key in the WeakHashMap doesn't prevent it from being garbage collected, so if there is no other reference to the key you put in the map, the GC can release that instance. Therefore, after you assign a new instance to emp1, only the map contains a reference to the original instance it referred to, and the GC can release it.

Here's the relevant Javadoc reference :

An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector

EDIT :

As for how the implementation of WeakHashMap is different, the Entry of a WeakHashMap extends WeakReference<Object>, which is an instance that refers to another instance (the key of the entry in this case) and doesn't prevent its referent from being released by the GC.

How to directly initialize a HashMap (in a literal way)?

All Versions

In case you happen to need just a single entry: There is Collections.singletonMap("key", "value").

For Java Version 9 or higher:

Yes, this is possible now. In Java 9 a couple of factory methods have been added that simplify the creation of maps :

// this works for up to 10 elements:
Map<String, String> test1 = Map.of(
"a", "b",
"c", "d"
);

// this works for any number of elements:
import static java.util.Map.entry;
Map<String, String> test2 = Map.ofEntries(
entry("a", "b"),
entry("c", "d")
);

In the example above both test and test2 will be the same, just with different ways of expressing the Map. The Map.of method is defined for up to ten elements in the map, while the Map.ofEntries method will have no such limit.

Note that in this case the resulting map will be an immutable map. If you want the map to be mutable, you could copy it again, e.g. using mutableMap = new HashMap<>(Map.of("a", "b"));. Also note that in this case keys and values must not be null.

(See also JEP 269 and the Javadoc)

For up to Java Version 8:

No, you will have to add all the elements manually. You can use an initializer in an anonymous subclass to make the syntax a little bit shorter:

Map<String, String> myMap = new HashMap<String, String>() {{
put("a", "b");
put("c", "d");
}};

However, the anonymous subclass might introduce unwanted behavior in some cases. This includes for example:

  • It generates an additional class which increases memory consumption, disk space consumption and startup-time
  • In case of a non-static method: It holds a reference to the object the creating method was called upon. That means the object of the outer class cannot be garbage collected while the created map object is still referenced, thus blocking additional memory

Using a function for initialization will also enable you to generate a map in an initializer, but avoids nasty side-effects:

Map<String, String> myMap = createMap();

private static Map<String, String> createMap() {
Map<String,String> myMap = new HashMap<String,String>();
myMap.put("a", "b");
myMap.put("c", "d");
return myMap;
}

Java: Constructing a Map from a single expression?

Guava has that with its ImmutableMap:

final Map<Foo, Bar> map = ImmutableMap.of(foo1, bar1, foo2, bar2, etc, etc);

Bonus: ImmutableMap's name is not a lie ;)

Note that there are 5 versions of the .of() method, so up to 5 key/value pairs. A more generic way is to use a builder:

final Map<Foo, Bar> map = ImmutableMap.<Foo, Bar>builder()
.put(foo1, bar1)
.put(foo2, bar2)
.put(foo3, bar3)
.put(etc, etc)
.build();

Note, however: this map does not accept null keys or values.

Alternatively, here is a poor man's version of ImmutableMap. It uses a classical builder pattern. Note that it does not check for nulls:

public final class MapBuilder<K, V>
{
private final Map<K, V> map = new HashMap<K, V>();

public MapBuilder<K, V> put(final K key, final V value)
{
map.put(key, value);
return this;
}

public Map<K, V> build()
{
// Return a mutable copy, so that the builder can be reused
return new HashMap<K, V>(map);
}

public Map<K, V> immutable()
{
// Return a copy wrapped into Collections.unmodifiableMap()
return Collections.unmodifiableMap(build());
}
}

Then you can use:

final Map<K, V> map = new MapBuilder<K, V>().put(...).put(...).immutable();

String Vs Stringbuffer as HashMap key

StringBuilder/Buffer do not override hashCode and equals. This means each instance of the object should be a unique hash code and the value or state of it does not matter. You should use the String for a key.

StringBuilder/Buffer is also mutable which is generally not a good idea to use as a key for a HashMap since storing the value under it can cause the value to be inaccessible after modification.

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/StringBuilder.java



Related Topics



Leave a reply



Submit