Java 8 Map 中 putIfAbsent 和 computeIfAbsent 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48183999/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between putIfAbsent and computeIfAbsent in Java 8 Map ?
提问by Adelin
Reading an interesting articles the guys claims that the difference between the two function are:
阅读一篇有趣的文章,这些人声称这两个功能之间的区别是:
Both functions aspire to add an element if the specified Key is not already present in Map.
putIfAbsent adds an element with the specified Value whereas computeIfAbsent adds an element with the value computed using the Key. http://www.buggybread.com/2014/10/java-8-difference-between-map.html
如果指定的 Key 不存在于 Map 中,这两个函数都希望添加一个元素。
putIfAbsent 添加具有指定值的元素,而 computeIfAbsent 添加具有使用 Key 计算的值的元素。 http://www.buggybread.com/2014/10/java-8-difference-between-map.html
And
和
We've seen that putIfAbsent removes the imperative way of having to define the if-statement, but what if fetching the Java articles is really hurting our performance?
To optimise this, we don't want to fetch the articles until we're really sure we need them — meaning we need to know if the key is absent before fetching the articles. http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
我们已经看到 putIfAbsent 消除了必须定义 if 语句的命令式方式,但是如果获取 Java 文章真的损害了我们的性能怎么办?
为了优化这一点,我们不想获取文章,直到我们真的确定需要它们——这意味着我们需要在获取文章之前知道键是否不存在。 http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
I didn't ready understand what are the differences can you please elaborate more on these two functions ?
我还没准备好了解有什么区别,请您详细说明这两个功能吗?
采纳答案by Andreas
Difference #1
差异#1
computeIfAbsent
takes a mapping function, that is called to obtain the value if the key is missing.
computeIfAbsent
采用一个映射函数,如果键丢失,则调用该函数以获取值。
putIfAbsent
takes the value directly.
putIfAbsent
直接取值。
If the value is expensive to obtain, then putIfAbsent
wastes that if the key already exists.
如果该值的获取代价高昂,那么putIfAbsent
如果该键已经存在,则浪费该值。
A common "expensive" value is e.g. new ArrayList<>()
for when you're creating a Map<K, List<V>>
, where creating a new list when the key already exists (which then discards the new list) generates unnecessary garbage.
一个常见的“昂贵”值是例如new ArrayList<>()
当您创建 a 时Map<K, List<V>>
,当键已经存在时创建一个新列表(然后丢弃新列表)会产生不必要的垃圾。
Difference #2
差异#2
computeIfAbsent
returns "the current (existing or computed) value associated with the specified key, or null if the computed value is null".
computeIfAbsent
返回“与指定键关联的当前(现有或计算出的)值,如果计算出的值为空,则返回空值”。
putIfAbsent
returns "the previous value associated with the specified key, or null if there was no mapping for the key".
putIfAbsent
返回“与指定键关联的前一个值,如果没有该键的映射,则返回 null”。
So, if the key already exists, they return the same thing, but if the key is missing, computeIfAbsent
returns the computed value, while putIfAbsent
return null.
所以,如果键已经存在,它们返回相同的东西,但如果键丢失,则computeIfAbsent
返回计算值,而putIfAbsent
返回空值。
Difference #3
差异#3
Both method define "absent" as key missing or existing value is null, but:
这两种方法都将“不存在”定义为键缺失或现有值为空,但是:
computeIfAbsent
will not put a null value if the key is absent.
computeIfAbsent
如果键不存在,则不会放置空值。
putIfAbsent
will put the value if the key is absent, even if the value is null.
putIfAbsent
如果键不存在,即使该值为空,也会放置该值。
It makes no difference for future calls to computeIfAbsent
, putIfAbsent
, and get
calls, but it does make a difference to calls like getOrDefault
and containsKey
.
这使得对未来没有什么区别调用computeIfAbsent
,putIfAbsent
以及get
调用,但它确实像呼叫差异getOrDefault
和containsKey
。
回答by Eran
Suppose you have a Map<String,ValueClass>
.
假设你有一个Map<String,ValueClass>
.
map.putIfAbsent("key", new ValueClass());
will create a ValueClass
instance anyway, even if the "key" key is already in the Map
. This would just create an unnecessary instance.
ValueClass
无论如何都会创建一个实例,即使“key”键已经在Map
. 这只会创建一个不必要的实例。
On the other hand
另一方面
map.computeIfAbsent("key", k -> new ValueClass());
will only create a ValueClass
instance if the "key" key is not already in the Map
(or is mapped to a null
value).
ValueClass
如果“键”键不在Map
(或映射到null
值)中,则只会创建一个实例。
Therefore computeIfAbsent
is more efficient.
因此computeIfAbsent
效率更高。
putIfAbsent
is equivalent to:
putIfAbsent
相当于:
ValueClass value = new ValueClass();
if (map.get("key") == null) {
map.put("key",value);
}
while computeIfAbsent
is equivalent to:
whilecomputeIfAbsent
相当于:
if (map.get("key") == null) {
map.put("key",new ValueClass());
}
Another small difference between the two methods is that computeIfAbsent
will not put a null
value for an absent key. putIfAbsent
will.
两种方法之间的另一个小区别是computeIfAbsent
不会null
为不存在的键放置值。putIfAbsent
将要。
回答by Jesper
You can understand the difference by carefully looking at the method signatures:
您可以通过仔细查看方法签名来理解差异:
putIfAbsent
takes a key and value, and puts the value in the map if there is no value for that key in the map.computeIfAbsent
takes a key and aFunction
. If there is no value for that key in the map, the function is called to create the value, which is then put in the map.
putIfAbsent
接受一个键和值,如果映射中没有该键的值,则将该值放入映射中。computeIfAbsent
需要一把钥匙和一个Function
. 如果映射中没有该键的值,则调用该函数来创建该值,然后将该值放入映射中。
If you already have the value, use putIfAbsent
.
如果您已经拥有该值,请使用putIfAbsent
.
If you don't have the value yet and creating the value is an expensive operation (for example, the value has to be looked up in a database), then use computeIfAbsent
, so that the expensive operation doesn't need to be performed in case the map already contains a value for the specified key.
如果您还没有该值并且创建该值是一项代价高昂的操作(例如,必须在数据库中查找该值),则使用computeIfAbsent
,这样就不需要执行代价高昂的操作,以防万一映射已包含指定键的值。
回答by minotna
V putIfAbsent(K key, V value)
- If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
V putIfAbsent(K key, V value)
- 如果指定的键尚未与值关联(或映射为 null),则尝试使用给定的映射函数计算其值并将其输入此映射,除非为 null。
V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
- If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
- 如果指定的键尚未与值关联(或映射为 null),则尝试使用给定的映射函数计算其值并将其输入此映射,除非为 null。
Reading documentation can give you more obvious answer. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html
阅读文档可以给你更明显的答案。 https://docs.oracle.com/javase/8/docs/api/java/util/Map.html
回答by zlakad
Maybe the default implementations can clarify a little bit more....
也许默认实现可以澄清一点....
default V putIfAbsent?(K key, V value)
The default implementation is equivalent to, for this map:
default V putIfAbsent?(K key, V value)
对于此映射,默认实现等效于:
V v = map.get(key);
if (v == null)
v = map.put(key, value);
return v;
On the other hand:
另一方面:
default V computeIfAbsent?(K key,
Function<? super K,? extends V> mappingFunction)
is equivalent to:
相当于:
if (map.get(key) == null) {
V newValue = mappingFunction.apply(key);
if (newValue != null)
map.put(key, newValue);
}
回答by Jain
Take this simple Example for putIfAbsent():
Map myMap = new HashMap();
myMap.put(1,"ABC");
myMap.put(2,"XYZ");
myMap.put(3,"GHI");
//Output of map till this point is : 1-> "ABC", 2-> "XYZ", 3-> "GHI"
myMap.putIfAbsent(3,"cx");
//Output of map till this point is : 1-> "ABC", 2-> "XYZ", 3-> "GHI"
cx will be value of 3 if there is no Value of 3 in the map already.
回答by S Kumar
This question has already been answered. I took a little time to understand ("expensive operation doesn't need to be performed in case the map already contains a value for the specified key in computeIfAbsent") I am putting my understanding here. Hope this will be helpful to others:
这个问题已经有了答案。我花了一点时间来理解(“如果映射已经包含computeIfAbsent 中指定键的值,则不需要执行昂贵的操作”)我将我的理解放在这里。希望这对其他人有帮助:
putIfAbsent() behaves simply as put() when map already contains the value for the specified key. putIfAbsent() only checks whether key is null or not. If it is not null then it returns the value and then map fetch that value again.
当 map 已包含指定键的值时, putIfAbsent() 的行为与 put() 类似。putIfAbsent() 只检查 key 是否为空。如果它不为空,则返回该值,然后 map 再次获取该值。
However, in computeIfAbsent() there is null check for both key and value. During null check for value, if it is not null then existing value from the map object is assigned to newValue and it is returned. That's why there is no need to again fetch the value as existing value from map is re-used.
但是,在computeIfAbsent() 中,键和值都进行了空检查。在空值检查期间,如果它不是空值,则将地图对象中的现有值分配给 newValue 并返回。这就是为什么不需要再次获取该值的原因,因为 map 中的现有值已被重新使用。
Refer to following program for reference:
参考以下程序:
public class MapTest1 {
public static final String AJAY_DEVGAN = "Ajay Devgn";
public static final String AUTOBIOGRAPHY = "Autobiography";
public static void main(String[] args) {
MapTest1 mt = new MapTest1();
mt.testPutCompute();
}
private void testPutCompute() {
Map<String, List<String>> movies = getMovieObject();
System.out.println("\nCalling putIfAbsent method.....");
//System.out.println(movies.get(AJAY_DEVGAN));
//movies.put(AJAY_DEVGAN, getAjayDevgnMovies());
movies.putIfAbsent(AJAY_DEVGAN, getAjayDevgnMovies());
System.out.println("\nCalling computeIfAbsent method......");
//System.out.println(movies.get(AUTOBIOGRAPHY));
movies.computeIfAbsent(AUTOBIOGRAPHY, t -> getAutobiographyMovies());
}
private Map<String, List<String>> getMovieObject() {
Map<String, List<String>> movies = new HashMap<>();
movies.put(AJAY_DEVGAN, getAjayDevgnMovies());
movies.put(AUTOBIOGRAPHY, getAutobiographyMovies());
System.out.println(movies);
return movies;
}
private List<String> getAutobiographyMovies() {
System.out.println("Getting autobiography movies");
List<String> list = new ArrayList<>();
list.add("M.S. Dhoni - The Untold Story");
list.add("Sachin: A Billion Dreams");
return list;
}
private List<String> getAjayDevgnMovies() {
System.out.println("Getting Ajay Devgn Movies");
List<String> ajayDevgnMovies = new ArrayList<>();
ajayDevgnMovies.add("Jigar");
ajayDevgnMovies.add("Pyar To Hona Hi Tha");
return ajayDevgnMovies;
}
}
Refer to following code for putIfAbsent() and computeIfAbsent() from interface Map.class
接口 Map.class 中的 putIfAbsent() 和 computeIfAbsent() 参考以下代码
public interface Map<K,V> {
.....
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
.........
}