Manoj Suthar
Manoj Suthar

Reputation: 1455

How does java.util.Map's getOrDefault() work?

I noticed that if I do map.getOrDefault("key1", new Object()), even if object is present for key1 in the map, new Object() is created. Though it is not returned by the method but it still creates it. For example,

public class Empl {
    private int id;
    private String name;

    public Empl(String name) {
        // TODO Auto-generated constructor stub
        System.out.println(name);
        this.name = name;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return name+id;
    }
}

running following,

Map<String, Empl> map = new HashMap<String, Empl>();
Empl imp = new Empl("timon");
map.put("1", imp);
System.out.println(map.getOrDefault("1", new Empl("dumnba")));

gives this output:

timon
dumnba
timon0

Shouldn't the default object be created only if it is not there in the map ? What is the reason if not ?

Upvotes: 32

Views: 54893

Answers (5)

Santiago Ordax
Santiago Ordax

Reputation: 63

Since Java 8, if you want to avoid default parameter being evaluated you can use Optional's orElseGet method:

System.out.println(Optional.ofNullable(map.get("1"))
    .orElseGet(() -> new Empl("dumnba")));

If key "1" is found orElseGet will return the corresponding map's value. Otherwise it will return the result of evaluating the passed function. It'll be evaluated (and class Empl instantiated) only if key is not found.

Of course this will always instantiate an Optional when key is found.

Upvotes: 0

khelwood
khelwood

Reputation: 59166

All the arguments to a function are evaluated before the function is executed. Java needs to evaluate new Empl("dumnba") so it can pass the result into getOrDefault. It can't know before getOrDefault is called that one of the arguments is not going to be required.

If you want to provide a default that is not computed unless needed, you can use computeIfAbsent. For this, you pass in a function, and that function is only executed if the default value is required.

map.computeIfAbsent("1", key -> new Empl("dumnba"))

Upvotes: 9

look in the java 8 implementation:

default V getOrDefault(Object key, V defaultValue) {
    V v;
    return (((v = get(key)) != null) || containsKey(key))
        ? v
        : defaultValue;
}

the doc specifies:

Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key. ault

it will return the default is not present in the map

example:

    Map<String, String> map = new HashMap<>();

    map.put("1", "Foo");
    //search for the entry with key==1, since present, returns foo
    System.out.println(map.getOrDefault("1", "dumnba"));
    //search for the entry with key==2, since not present, returns dumnba
    System.out.println(map.getOrDefault("2", "dumnba"));

Upvotes: 7

Jon Skeet
Jon Skeet

Reputation: 1502406

Shouldn't the default object be created only if it is not there in the map ?

How could that be the case? This call:

map.getOrDefault("1", new Empl("dumnba"))

is equivalent to:

String arg0 = "1";
Empl arg1 = new Empl("dumnba");
map.getOrDefault(arg0, arg1);

In other words, all arguments are evaluated before being passed to the method.

You could potentially use computeIfAbsent instead, but that will modify the map if the key was absent, which you may not want:

System.out.println(map.computeIfAbsent("1", k -> new Empl("dumnba")));

Upvotes: 44

Yoni
Yoni

Reputation: 10321

This is not because of how the map is implemented, it is because of how Java works. The runtime interpreter has to create the object first (the new Empl part) before it can actually invoke the method (the getOrDefault part).

Upvotes: 1

Related Questions