Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
ad59a26e
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
ad59a26e
编写于
4月 16, 2013
作者:
C
chegar
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
29a714c1
6019b1d8
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
2097 addition
and
51 deletion
+2097
-51
src/share/classes/java/util/Collections.java
src/share/classes/java/util/Collections.java
+333
-18
src/share/classes/java/util/HashMap.java
src/share/classes/java/util/HashMap.java
+271
-5
src/share/classes/java/util/Hashtable.java
src/share/classes/java/util/Hashtable.java
+259
-16
src/share/classes/java/util/Map.java
src/share/classes/java/util/Map.java
+614
-1
src/share/classes/java/util/concurrent/ConcurrentMap.java
src/share/classes/java/util/concurrent/ConcurrentMap.java
+26
-11
test/java/util/Map/Defaults.java
test/java/util/Map/Defaults.java
+594
-0
未找到文件。
src/share/classes/java/util/Collections.java
浏览文件 @
ad59a26e
...
@@ -28,6 +28,9 @@ import java.io.Serializable;
...
@@ -28,6 +28,9 @@ import java.io.Serializable;
import
java.io.ObjectOutputStream
;
import
java.io.ObjectOutputStream
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.reflect.Array
;
import
java.lang.reflect.Array
;
import
java.util.function.BiConsumer
;
import
java.util.function.BiFunction
;
import
java.util.function.Function
;
/**
/**
* This class consists exclusively of static methods that operate on or return
* This class consists exclusively of static methods that operate on or return
...
@@ -264,8 +267,7 @@ public class Collections {
...
@@ -264,8 +267,7 @@ public class Collections {
}
}
private
static
<
T
>
private
static
<
T
>
int
indexedBinarySearch
(
List
<?
extends
Comparable
<?
super
T
>>
list
,
T
key
)
int
indexedBinarySearch
(
List
<?
extends
Comparable
<?
super
T
>>
list
,
T
key
)
{
{
int
low
=
0
;
int
low
=
0
;
int
high
=
list
.
size
()-
1
;
int
high
=
list
.
size
()-
1
;
...
@@ -441,21 +443,21 @@ public class Collections {
...
@@ -441,21 +443,21 @@ public class Collections {
/**
/**
* Randomly permutes the specified list using a default source of
* Randomly permutes the specified list using a default source of
* randomness. All permutations occur with approximately equal
* randomness. All permutations occur with approximately equal
* likelihood.
<p>
* likelihood.
*
*
* The hedge "approximately" is used in the foregoing description because
*
<p>
The hedge "approximately" is used in the foregoing description because
* default source of randomness is only approximately an unbiased source
* default source of randomness is only approximately an unbiased source
* of independently chosen bits. If it were a perfect source of randomly
* of independently chosen bits. If it were a perfect source of randomly
* chosen bits, then the algorithm would choose permutations with perfect
* chosen bits, then the algorithm would choose permutations with perfect
* uniformity.
<p>
* uniformity.
*
*
*
This implementation traverses the list backwards, from the last elemen
t
*
<p>This implementation traverses the list backwards, from the las
t
*
up to the second, repeatedly swapping a randomly selected element into
*
element up to the second, repeatedly swapping a randomly selected element
* the "current position". Elements are randomly selected from the
*
into
the "current position". Elements are randomly selected from the
* portion of the list that runs from the first element to the current
* portion of the list that runs from the first element to the current
* position, inclusive.
<p>
* position, inclusive.
*
*
* This method runs in linear time. If the specified list does not
*
<p>
This method runs in linear time. If the specified list does not
* implement the {@link RandomAccess} interface and is large, this
* implement the {@link RandomAccess} interface and is large, this
* implementation dumps the specified list into an array before shuffling
* implementation dumps the specified list into an array before shuffling
* it, and dumps the shuffled array back into the list. This avoids the
* it, and dumps the shuffled array back into the list. This avoids the
...
@@ -469,9 +471,10 @@ public class Collections {
...
@@ -469,9 +471,10 @@ public class Collections {
public
static
void
shuffle
(
List
<?>
list
)
{
public
static
void
shuffle
(
List
<?>
list
)
{
Random
rnd
=
r
;
Random
rnd
=
r
;
if
(
rnd
==
null
)
if
(
rnd
==
null
)
r
=
rnd
=
new
Random
();
r
=
rnd
=
new
Random
();
// harmless race.
shuffle
(
list
,
rnd
);
shuffle
(
list
,
rnd
);
}
}
private
static
Random
r
;
private
static
Random
r
;
/**
/**
...
@@ -1391,6 +1394,67 @@ public class Collections {
...
@@ -1391,6 +1394,67 @@ public class Collections {
public
int
hashCode
()
{
return
m
.
hashCode
();}
public
int
hashCode
()
{
return
m
.
hashCode
();}
public
String
toString
()
{
return
m
.
toString
();}
public
String
toString
()
{
return
m
.
toString
();}
// Override default methods in Map
@Override
@SuppressWarnings
(
"unchecked"
)
public
V
getOrDefault
(
Object
k
,
V
defaultValue
)
{
// Safe cast as we don't change the value
return
((
Map
<
K
,
V
>)
m
).
getOrDefault
(
k
,
defaultValue
);
}
@Override
public
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
m
.
forEach
(
action
);
}
@Override
public
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
/**
/**
* We need this class in addition to UnmodifiableSet as
* We need this class in addition to UnmodifiableSet as
* Map.Entries themselves permit modification of the backing Map
* Map.Entries themselves permit modification of the backing Map
...
@@ -1590,9 +1654,9 @@ public class Collections {
...
@@ -1590,9 +1654,9 @@ public class Collections {
* </pre>
* </pre>
* Failure to follow this advice may result in non-deterministic behavior.
* Failure to follow this advice may result in non-deterministic behavior.
*
*
* <p>The returned collection does <i>not</i> pass the
<tt>hashCode</tt>
* <p>The returned collection does <i>not</i> pass the
{@code hashCode}
* and
<tt>equals</tt>
operations through to the backing collection, but
* and
{@code equals}
operations through to the backing collection, but
* relies on
<tt>Object</tt>
's equals and hashCode methods. This is
* relies on
{@code Object}
's equals and hashCode methods. This is
* necessary to preserve the contracts of these operations in the case
* necessary to preserve the contracts of these operations in the case
* that the backing collection is a set or a list.<p>
* that the backing collection is a set or a list.<p>
*
*
...
@@ -2107,6 +2171,57 @@ public class Collections {
...
@@ -2107,6 +2171,57 @@ public class Collections {
public
String
toString
()
{
public
String
toString
()
{
synchronized
(
mutex
)
{
return
m
.
toString
();}
synchronized
(
mutex
)
{
return
m
.
toString
();}
}
}
// Override default methods in Map
@Override
public
V
getOrDefault
(
Object
k
,
V
defaultValue
)
{
synchronized
(
mutex
)
{
return
m
.
getOrDefault
(
k
,
defaultValue
);}
}
@Override
public
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
synchronized
(
mutex
)
{
m
.
forEach
(
action
);}
}
@Override
public
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
synchronized
(
mutex
)
{
m
.
replaceAll
(
function
);}
}
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
synchronized
(
mutex
)
{
return
m
.
putIfAbsent
(
key
,
value
);}
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
synchronized
(
mutex
)
{
return
m
.
remove
(
key
,
value
);}
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
synchronized
(
mutex
)
{
return
m
.
replace
(
key
,
oldValue
,
newValue
);}
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
synchronized
(
mutex
)
{
return
m
.
replace
(
key
,
value
);}
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
synchronized
(
mutex
)
{
return
m
.
computeIfAbsent
(
key
,
mappingFunction
);}
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
synchronized
(
mutex
)
{
return
m
.
computeIfPresent
(
key
,
remappingFunction
);}
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
synchronized
(
mutex
)
{
return
m
.
compute
(
key
,
remappingFunction
);}
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
synchronized
(
mutex
)
{
return
m
.
merge
(
key
,
value
,
remappingFunction
);}
}
private
void
writeObject
(
ObjectOutputStream
s
)
throws
IOException
{
private
void
writeObject
(
ObjectOutputStream
s
)
throws
IOException
{
synchronized
(
mutex
)
{
s
.
defaultWriteObject
();}
synchronized
(
mutex
)
{
s
.
defaultWriteObject
();}
}
}
...
@@ -2326,6 +2441,8 @@ public class Collections {
...
@@ -2326,6 +2441,8 @@ public class Collections {
}
}
public
Iterator
<
E
>
iterator
()
{
public
Iterator
<
E
>
iterator
()
{
// JDK-6363904 - unwrapped iterator could be typecast to
// ListIterator with unsafe set()
final
Iterator
<
E
>
it
=
c
.
iterator
();
final
Iterator
<
E
>
it
=
c
.
iterator
();
return
new
Iterator
<
E
>()
{
return
new
Iterator
<
E
>()
{
public
boolean
hasNext
()
{
return
it
.
hasNext
();
}
public
boolean
hasNext
()
{
return
it
.
hasNext
();
}
...
@@ -2652,7 +2769,7 @@ public class Collections {
...
@@ -2652,7 +2769,7 @@ public class Collections {
public
List
<
E
>
subList
(
int
fromIndex
,
int
toIndex
)
{
public
List
<
E
>
subList
(
int
fromIndex
,
int
toIndex
)
{
return
new
CheckedRandomAccessList
<>(
return
new
CheckedRandomAccessList
<>(
list
.
subList
(
fromIndex
,
toIndex
),
type
);
list
.
subList
(
fromIndex
,
toIndex
),
type
);
}
}
}
}
...
@@ -2717,14 +2834,24 @@ public class Collections {
...
@@ -2717,14 +2834,24 @@ public class Collections {
throw
new
ClassCastException
(
badValueMsg
(
value
));
throw
new
ClassCastException
(
badValueMsg
(
value
));
}
}
private
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
typeCheck
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
func
)
{
Objects
.
requireNonNull
(
func
);
return
(
k
,
v
)
->
{
V
newValue
=
func
.
apply
(
k
,
v
);
typeCheck
(
k
,
newValue
);
return
newValue
;
};
}
private
String
badKeyMsg
(
Object
key
)
{
private
String
badKeyMsg
(
Object
key
)
{
return
"Attempt to insert "
+
key
.
getClass
()
+
return
"Attempt to insert "
+
key
.
getClass
()
+
" key into map with key type "
+
keyType
;
" key into map with key type "
+
keyType
;
}
}
private
String
badValueMsg
(
Object
value
)
{
private
String
badValueMsg
(
Object
value
)
{
return
"Attempt to insert "
+
value
.
getClass
()
+
return
"Attempt to insert "
+
value
.
getClass
()
+
" value into map with value type "
+
valueType
;
" value into map with value type "
+
valueType
;
}
}
CheckedMap
(
Map
<
K
,
V
>
m
,
Class
<
K
>
keyType
,
Class
<
V
>
valueType
)
{
CheckedMap
(
Map
<
K
,
V
>
m
,
Class
<
K
>
keyType
,
Class
<
V
>
valueType
)
{
...
@@ -2768,7 +2895,7 @@ public class Collections {
...
@@ -2768,7 +2895,7 @@ public class Collections {
Object
v
=
e
.
getValue
();
Object
v
=
e
.
getValue
();
typeCheck
(
k
,
v
);
typeCheck
(
k
,
v
);
checked
.
add
(
checked
.
add
(
new
AbstractMap
.
SimpleImmutableEntry
<>((
K
)
k
,
(
V
)
v
));
new
AbstractMap
.
SimpleImmutableEntry
<>((
K
)
k
,
(
V
)
v
));
}
}
for
(
Map
.
Entry
<
K
,
V
>
e
:
checked
)
for
(
Map
.
Entry
<
K
,
V
>
e
:
checked
)
m
.
put
(
e
.
getKey
(),
e
.
getValue
());
m
.
put
(
e
.
getKey
(),
e
.
getValue
());
...
@@ -2782,6 +2909,74 @@ public class Collections {
...
@@ -2782,6 +2909,74 @@ public class Collections {
return
entrySet
;
return
entrySet
;
}
}
// Override default methods in Map
@Override
public
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
m
.
forEach
(
action
);
}
@Override
public
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
m
.
replaceAll
(
typeCheck
(
function
));
}
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
typeCheck
(
key
,
value
);
return
m
.
putIfAbsent
(
key
,
value
);
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
return
m
.
remove
(
key
,
value
);
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
typeCheck
(
key
,
newValue
);
return
m
.
replace
(
key
,
oldValue
,
newValue
);
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
typeCheck
(
key
,
value
);
return
m
.
replace
(
key
,
value
);
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
Objects
.
requireNonNull
(
mappingFunction
);
return
m
.
computeIfAbsent
(
key
,
k
->
{
V
value
=
mappingFunction
.
apply
(
k
);
typeCheck
(
k
,
value
);
return
value
;
});
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
return
m
.
computeIfPresent
(
key
,
typeCheck
(
remappingFunction
));
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
return
m
.
compute
(
key
,
typeCheck
(
remappingFunction
));
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
Objects
.
requireNonNull
(
remappingFunction
);
return
m
.
merge
(
key
,
value
,
(
v1
,
v2
)
->
{
V
newValue
=
remappingFunction
.
apply
(
v1
,
v2
);
typeCheck
(
null
,
newValue
);
return
newValue
;
});
}
/**
/**
* We need this class in addition to CheckedSet as Map.Entry permits
* We need this class in addition to CheckedSet as Map.Entry permits
* modification of the backing Map via the setValue operation. This
* modification of the backing Map via the setValue operation. This
...
@@ -3456,6 +3651,67 @@ public class Collections {
...
@@ -3456,6 +3651,67 @@ public class Collections {
public
int
hashCode
()
{
return
0
;}
public
int
hashCode
()
{
return
0
;}
// Override default methods in Map
@Override
@SuppressWarnings
(
"unchecked"
)
public
V
getOrDefault
(
Object
k
,
V
defaultValue
)
{
return
defaultValue
;
}
@Override
public
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
Objects
.
requireNonNull
(
action
);
}
@Override
public
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
Objects
.
requireNonNull
(
function
);
}
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
// Preserves singleton property
// Preserves singleton property
private
Object
readResolve
()
{
private
Object
readResolve
()
{
return
EMPTY_MAP
;
return
EMPTY_MAP
;
...
@@ -3619,6 +3875,65 @@ public class Collections {
...
@@ -3619,6 +3875,65 @@ public class Collections {
return
values
;
return
values
;
}
}
// Override default methods in Map
@Override
public
V
getOrDefault
(
Object
key
,
V
defaultValue
)
{
return
eq
(
key
,
k
)
?
v
:
defaultValue
;
}
@Override
public
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
action
.
accept
(
k
,
v
);
}
@Override
public
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
throw
new
UnsupportedOperationException
();
}
}
}
// Miscellaneous
// Miscellaneous
...
...
src/share/classes/java/util/HashMap.java
浏览文件 @
ad59a26e
/*
/*
* Copyright (c) 1997, 201
2
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 201
3
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -24,7 +24,11 @@
...
@@ -24,7 +24,11 @@
*/
*/
package
java.util
;
package
java.util
;
import
java.io.*
;
import
java.io.*
;
import
java.util.function.Consumer
;
import
java.util.function.BiFunction
;
import
java.util.function.Function
;
/**
/**
* Hash table based implementation of the <tt>Map</tt> interface. This
* Hash table based implementation of the <tt>Map</tt> interface. This
...
@@ -376,6 +380,13 @@ public class HashMap<K,V>
...
@@ -376,6 +380,13 @@ public class HashMap<K,V>
return
null
==
entry
?
null
:
entry
.
getValue
();
return
null
==
entry
?
null
:
entry
.
getValue
();
}
}
@Override
public
V
getOrDefault
(
Object
key
,
V
defaultValue
)
{
Entry
<
K
,
V
>
entry
=
getEntry
(
key
);
return
(
entry
==
null
)
?
defaultValue
:
entry
.
getValue
();
}
/**
/**
* Returns <tt>true</tt> if this map contains a mapping for the
* Returns <tt>true</tt> if this map contains a mapping for the
* specified key.
* specified key.
...
@@ -603,6 +614,261 @@ public class HashMap<K,V>
...
@@ -603,6 +614,261 @@ public class HashMap<K,V>
return
(
e
==
null
?
null
:
e
.
value
);
return
(
e
==
null
?
null
:
e
.
value
);
}
}
// optimized implementations of default methods in Map
@Override
public
V
putIfAbsent
(
K
key
,
V
value
)
{
if
(
table
==
EMPTY_TABLE
)
{
inflateTable
(
threshold
);
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
table
[
i
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
if
(
e
.
value
!=
null
)
{
return
e
.
value
;
}
e
.
value
=
value
;
modCount
++;
e
.
recordAccess
(
this
);
return
null
;
}
}
modCount
++;
addEntry
(
hash
,
key
,
value
,
i
);
return
null
;
}
@Override
public
boolean
remove
(
Object
key
,
Object
value
)
{
if
(
isEmpty
())
{
return
false
;
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
prev
=
(
Entry
<
K
,
V
>)
table
[
i
];
Entry
<
K
,
V
>
e
=
prev
;
while
(
e
!=
null
)
{
Entry
<
K
,
V
>
next
=
e
.
next
;
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
if
(!
Objects
.
equals
(
e
.
value
,
value
))
{
return
false
;
}
modCount
++;
size
--;
if
(
prev
==
e
)
table
[
i
]
=
next
;
else
prev
.
next
=
next
;
e
.
recordRemoval
(
this
);
return
true
;
}
prev
=
e
;
e
=
next
;
}
return
false
;
}
@Override
public
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
if
(
isEmpty
())
{
return
false
;
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
table
[
i
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
)
&&
Objects
.
equals
(
e
.
value
,
oldValue
))
{
e
.
value
=
newValue
;
e
.
recordAccess
(
this
);
return
true
;
}
}
return
false
;
}
@Override
public
V
replace
(
K
key
,
V
value
)
{
if
(
isEmpty
())
{
return
null
;
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
table
[
i
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
oldValue
=
e
.
value
;
e
.
value
=
value
;
e
.
recordAccess
(
this
);
return
oldValue
;
}
}
return
null
;
}
@Override
public
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
if
(
table
==
EMPTY_TABLE
)
{
inflateTable
(
threshold
);
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
table
[
i
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
oldValue
=
e
.
value
;
return
oldValue
==
null
?
(
e
.
value
=
mappingFunction
.
apply
(
key
))
:
oldValue
;
}
}
V
newValue
=
mappingFunction
.
apply
(
key
);
if
(
newValue
!=
null
)
{
modCount
++;
addEntry
(
hash
,
key
,
newValue
,
i
);
}
return
newValue
;
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
if
(
isEmpty
())
{
return
null
;
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
prev
=
(
Entry
<
K
,
V
>)
table
[
i
];
Entry
<
K
,
V
>
e
=
prev
;
while
(
e
!=
null
)
{
Entry
<
K
,
V
>
next
=
e
.
next
;
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
oldValue
=
e
.
value
;
if
(
oldValue
==
null
)
break
;
V
newValue
=
remappingFunction
.
apply
(
key
,
oldValue
);
modCount
++;
if
(
newValue
==
null
)
{
size
--;
if
(
prev
==
e
)
table
[
i
]
=
next
;
else
prev
.
next
=
next
;
e
.
recordRemoval
(
this
);
}
else
{
e
.
value
=
newValue
;
e
.
recordAccess
(
this
);
}
return
newValue
;
}
prev
=
e
;
e
=
next
;
}
return
null
;
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
if
(
table
==
EMPTY_TABLE
)
{
inflateTable
(
threshold
);
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
prev
=
(
Entry
<
K
,
V
>)
table
[
i
];
Entry
<
K
,
V
>
e
=
prev
;
while
(
e
!=
null
)
{
Entry
<
K
,
V
>
next
=
e
.
next
;
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
oldValue
=
e
.
value
;
V
newValue
=
remappingFunction
.
apply
(
key
,
oldValue
);
if
(
newValue
!=
oldValue
)
{
modCount
++;
if
(
newValue
==
null
)
{
size
--;
if
(
prev
==
e
)
table
[
i
]
=
next
;
else
prev
.
next
=
next
;
e
.
recordRemoval
(
this
);
}
else
{
e
.
value
=
newValue
;
e
.
recordAccess
(
this
);
}
}
return
newValue
;
}
prev
=
e
;
e
=
next
;
}
V
newValue
=
remappingFunction
.
apply
(
key
,
null
);
if
(
newValue
!=
null
)
{
modCount
++;
addEntry
(
hash
,
key
,
newValue
,
i
);
}
return
newValue
;
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
if
(
table
==
EMPTY_TABLE
)
{
inflateTable
(
threshold
);
}
int
hash
=
(
key
==
null
)
?
0
:
hash
(
key
);
int
i
=
indexFor
(
hash
,
table
.
length
);
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
prev
=
(
Entry
<
K
,
V
>)
table
[
i
];
Entry
<
K
,
V
>
e
=
prev
;
while
(
e
!=
null
)
{
Entry
<
K
,
V
>
next
=
e
.
next
;
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
oldValue
=
e
.
value
;
V
newValue
=
remappingFunction
.
apply
(
oldValue
,
value
);
modCount
++;
if
(
newValue
==
null
)
{
size
--;
if
(
prev
==
e
)
table
[
i
]
=
next
;
else
prev
.
next
=
next
;
e
.
recordRemoval
(
this
);
}
else
{
e
.
value
=
newValue
;
e
.
recordAccess
(
this
);
}
return
newValue
;
}
prev
=
e
;
e
=
next
;
}
if
(
value
!=
null
)
{
modCount
++;
addEntry
(
hash
,
key
,
value
,
i
);
}
return
value
;
}
// end of optimized implementations of default methods in Map
/**
/**
* Removes and returns the entry associated with the specified key
* Removes and returns the entry associated with the specified key
* in the HashMap. Returns null if the HashMap contains no mapping
* in the HashMap. Returns null if the HashMap contains no mapping
...
@@ -697,8 +963,8 @@ public class HashMap<K,V>
...
@@ -697,8 +963,8 @@ public class HashMap<K,V>
return
containsNullValue
();
return
containsNullValue
();
Entry
<?,?>[]
tab
=
table
;
Entry
<?,?>[]
tab
=
table
;
for
(
int
i
=
0
;
i
<
tab
.
length
;
i
++)
for
(
int
i
=
0
;
i
<
tab
.
length
;
i
++)
for
(
Entry
<?,?>
e
=
tab
[
i
]
;
e
!=
null
;
e
=
e
.
next
)
for
(
Entry
<?,?>
e
=
tab
[
i
]
;
e
!=
null
;
e
=
e
.
next
)
if
(
value
.
equals
(
e
.
value
))
if
(
value
.
equals
(
e
.
value
))
return
true
;
return
true
;
return
false
;
return
false
;
...
@@ -709,8 +975,8 @@ public class HashMap<K,V>
...
@@ -709,8 +975,8 @@ public class HashMap<K,V>
*/
*/
private
boolean
containsNullValue
()
{
private
boolean
containsNullValue
()
{
Entry
<?,?>[]
tab
=
table
;
Entry
<?,?>[]
tab
=
table
;
for
(
int
i
=
0
;
i
<
tab
.
length
;
i
++)
for
(
int
i
=
0
;
i
<
tab
.
length
;
i
++)
for
(
Entry
<?,?>
e
=
tab
[
i
]
;
e
!=
null
;
e
=
e
.
next
)
for
(
Entry
<?,?>
e
=
tab
[
i
]
;
e
!=
null
;
e
=
e
.
next
)
if
(
e
.
value
==
null
)
if
(
e
.
value
==
null
)
return
true
;
return
true
;
return
false
;
return
false
;
...
...
src/share/classes/java/util/Hashtable.java
浏览文件 @
ad59a26e
/*
/*
* Copyright (c) 1994, 201
2
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 201
3
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -24,7 +24,11 @@
...
@@ -24,7 +24,11 @@
*/
*/
package
java.util
;
package
java.util
;
import
java.io.*
;
import
java.io.*
;
import
java.util.function.BiConsumer
;
import
java.util.function.Function
;
import
java.util.function.BiFunction
;
/**
/**
* This class implements a hash table, which maps keys to values. Any
* This class implements a hash table, which maps keys to values. Any
...
@@ -455,6 +459,26 @@ public class Hashtable<K,V>
...
@@ -455,6 +459,26 @@ public class Hashtable<K,V>
}
}
}
}
private
void
addEntry
(
int
hash
,
K
key
,
V
value
,
int
index
)
{
modCount
++;
Entry
<?,?>
tab
[]
=
table
;
if
(
count
>=
threshold
)
{
// Rehash the table if the threshold is exceeded
rehash
();
tab
=
table
;
hash
=
hash
(
key
);
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
}
// Creates the new entry.
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
tab
[
index
]
=
new
Entry
<>(
hash
,
key
,
value
,
e
);
count
++;
}
/**
/**
* Maps the specified <code>key</code> to the specified
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* <code>value</code> in this hashtable. Neither the key nor the
...
@@ -492,21 +516,7 @@ public class Hashtable<K,V>
...
@@ -492,21 +516,7 @@ public class Hashtable<K,V>
}
}
}
}
modCount
++;
addEntry
(
hash
,
key
,
value
,
index
);
if
(
count
>=
threshold
)
{
// Rehash the table if the threshold is exceeded
rehash
();
tab
=
table
;
hash
=
hash
(
key
);
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
}
// Creates the new entry.
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
tab
[
index
]
=
new
Entry
<>(
hash
,
key
,
value
,
e
);
count
++;
return
null
;
return
null
;
}
}
...
@@ -892,6 +902,239 @@ public class Hashtable<K,V>
...
@@ -892,6 +902,239 @@ public class Hashtable<K,V>
return
h
;
return
h
;
}
}
@Override
public
synchronized
V
getOrDefault
(
Object
key
,
V
defaultValue
)
{
V
result
=
get
(
key
);
return
(
null
==
result
)
?
defaultValue
:
result
;
}
@Override
public
synchronized
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
Objects
.
requireNonNull
(
action
);
// explicit check required in case
// table is empty.
Entry
<?,?>[]
tab
=
table
;
for
(
Entry
<?,?>
entry
:
tab
)
{
while
(
entry
!=
null
)
{
action
.
accept
((
K
)
entry
.
key
,
(
V
)
entry
.
value
);
entry
=
entry
.
next
;
}
}
}
@Override
public
synchronized
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
Map
.
super
.
replaceAll
(
function
);
}
@Override
public
synchronized
V
putIfAbsent
(
K
key
,
V
value
)
{
Objects
.
requireNonNull
(
value
);
// Makes sure the key is not already in the hashtable.
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
entry
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(;
entry
!=
null
;
entry
=
entry
.
next
)
{
if
((
entry
.
hash
==
hash
)
&&
entry
.
key
.
equals
(
key
))
{
V
old
=
entry
.
value
;
if
(
old
==
null
)
{
entry
.
value
=
value
;
}
return
old
;
}
}
addEntry
(
hash
,
key
,
value
,
index
);
return
null
;
}
@Override
public
synchronized
boolean
remove
(
Object
key
,
Object
value
)
{
Objects
.
requireNonNull
(
value
);
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(
Entry
<
K
,
V
>
prev
=
null
;
e
!=
null
;
prev
=
e
,
e
=
e
.
next
)
{
if
((
e
.
hash
==
hash
)
&&
e
.
key
.
equals
(
key
)
&&
e
.
value
.
equals
(
value
))
{
modCount
++;
if
(
prev
!=
null
)
{
prev
.
next
=
e
.
next
;
}
else
{
tab
[
index
]
=
e
.
next
;
}
count
--;
e
.
value
=
null
;
return
true
;
}
}
return
false
;
}
@Override
public
synchronized
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
((
e
.
hash
==
hash
)
&&
e
.
key
.
equals
(
key
))
{
if
(
e
.
value
.
equals
(
oldValue
))
{
e
.
value
=
newValue
;
return
true
;
}
else
{
return
false
;
}
}
}
return
false
;
}
@Override
public
synchronized
V
replace
(
K
key
,
V
value
)
{
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
((
e
.
hash
==
hash
)
&&
e
.
key
.
equals
(
key
))
{
V
oldValue
=
e
.
value
;
e
.
value
=
value
;
return
oldValue
;
}
}
return
null
;
}
@Override
public
synchronized
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
Objects
.
requireNonNull
(
mappingFunction
);
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(;
e
!=
null
;
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
e
.
key
.
equals
(
key
))
{
// Hashtable not accept null value
return
e
.
value
;
}
}
V
newValue
=
mappingFunction
.
apply
(
key
);
if
(
newValue
!=
null
)
{
addEntry
(
hash
,
key
,
newValue
,
index
);
}
return
newValue
;
}
@Override
public
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
Objects
.
requireNonNull
(
remappingFunction
);
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(
Entry
<
K
,
V
>
prev
=
null
;
e
!=
null
;
prev
=
e
,
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
e
.
key
.
equals
(
key
))
{
V
newValue
=
remappingFunction
.
apply
(
key
,
e
.
value
);
if
(
newValue
==
null
)
{
modCount
++;
if
(
prev
!=
null
)
{
prev
.
next
=
e
.
next
;
}
else
{
tab
[
index
]
=
e
.
next
;
}
count
--;
}
else
{
e
.
value
=
newValue
;
}
return
newValue
;
}
}
return
null
;
}
@Override
public
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
Objects
.
requireNonNull
(
remappingFunction
);
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(
Entry
<
K
,
V
>
prev
=
null
;
e
!=
null
;
prev
=
e
,
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
Objects
.
equals
(
e
.
key
,
key
))
{
V
newValue
=
remappingFunction
.
apply
(
key
,
e
.
value
);
if
(
newValue
==
null
)
{
modCount
++;
if
(
prev
!=
null
)
{
prev
.
next
=
e
.
next
;
}
else
{
tab
[
index
]
=
e
.
next
;
}
count
--;
}
else
{
e
.
value
=
newValue
;
}
return
newValue
;
}
}
V
newValue
=
remappingFunction
.
apply
(
key
,
null
);
if
(
newValue
!=
null
)
{
addEntry
(
hash
,
key
,
newValue
,
index
);
}
return
newValue
;
}
@Override
public
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
Objects
.
requireNonNull
(
remappingFunction
);
Entry
<?,?>
tab
[]
=
table
;
int
hash
=
hash
(
key
);
int
index
=
(
hash
&
0x7FFFFFFF
)
%
tab
.
length
;
@SuppressWarnings
(
"unchecked"
)
Entry
<
K
,
V
>
e
=
(
Entry
<
K
,
V
>)
tab
[
index
];
for
(
Entry
<
K
,
V
>
prev
=
null
;
e
!=
null
;
prev
=
e
,
e
=
e
.
next
)
{
if
(
e
.
hash
==
hash
&&
e
.
key
.
equals
(
key
))
{
V
newValue
=
remappingFunction
.
apply
(
e
.
value
,
value
);
if
(
newValue
==
null
)
{
modCount
++;
if
(
prev
!=
null
)
{
prev
.
next
=
e
.
next
;
}
else
{
tab
[
index
]
=
e
.
next
;
}
count
--;
}
else
{
e
.
value
=
newValue
;
}
return
newValue
;
}
}
if
(
value
!=
null
)
{
addEntry
(
hash
,
key
,
value
,
index
);
}
return
value
;
}
/**
/**
* Save the state of the Hashtable to a stream (i.e., serialize it).
* Save the state of the Hashtable to a stream (i.e., serialize it).
*
*
...
...
src/share/classes/java/util/Map.java
浏览文件 @
ad59a26e
/*
/*
* Copyright (c) 1997, 201
1
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 201
3
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -25,6 +25,10 @@
...
@@ -25,6 +25,10 @@
package
java.util
;
package
java.util
;
import
java.util.function.BiConsumer
;
import
java.util.function.BiFunction
;
import
java.util.function.Function
;
/**
/**
* An object that maps keys to values. A map cannot contain duplicate keys;
* An object that maps keys to values. A map cannot contain duplicate keys;
* each key can map to at most one value.
* each key can map to at most one value.
...
@@ -475,4 +479,613 @@ public interface Map<K,V> {
...
@@ -475,4 +479,613 @@ public interface Map<K,V> {
*/
*/
int
hashCode
();
int
hashCode
();
// Defaultable methods
/**
* Returns the value to which the specified key is mapped,
* or {@code defaultValue} if this map contains no mapping
* for the key.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or
* {@code defaultValue} if this map contains no mapping for the key
* @throws ClassCastException if the key is of an inappropriate type for
* this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key is null and this map
* does not permit null keys
* (<a href="Collection.html#optional-restrictions">optional</a>)
*/
default
V
getOrDefault
(
Object
key
,
V
defaultValue
)
{
V
v
;
return
(((
v
=
get
(
key
))
!=
null
)
||
containsKey
(
key
))
?
v
:
defaultValue
;
}
/**
* Performs the given action on each entry in this map, in the order entries
* are returned by an entry set iterator (which may be unspecified), until
* all entries have been processed or the action throws an {@code Exception}.
* Exceptions thrown by the action are relayed to the caller.
*
* <p>The default implementation should be overridden by implementations if
* they can provide a more performant implementation than an iterator-based
* one.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec The default implementation is equivalent to, for this
* {@code map}:
* <pre> {@code
* for ((Map.Entry<K, V> entry : map.entrySet())
* action.accept(entry.getKey(), entry.getValue());
* }</pre>
*
* @param action The action to be performed for each entry
* @throws NullPointerException if the specified action is null
* @throws ConcurrentModificationException if an entry is found to be
* removed during iteration
* @since 1.8
*/
default
void
forEach
(
BiConsumer
<?
super
K
,
?
super
V
>
action
)
{
Objects
.
requireNonNull
(
action
);
for
(
Map
.
Entry
<
K
,
V
>
entry
:
entrySet
())
{
K
k
;
V
v
;
try
{
k
=
entry
.
getKey
();
v
=
entry
.
getValue
();
}
catch
(
IllegalStateException
ise
)
{
throw
new
ConcurrentModificationException
(
ise
);
}
action
.
accept
(
k
,
v
);
}
}
/**
* Replaces each entry's value with the result of invoking the given
* function on that entry, in the order entries are returned by an entry
* set iterator, until all entries have been processed or the function
* throws an exception.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec
* <p>The default implementation is equivalent to, for this {@code map}:
* <pre> {@code
* for ((Map.Entry<K, V> entry : map.entrySet())
* entry.setValue(function.apply(entry.getKey(), entry.getValue()));
* }</pre>
*
* @param function the function to apply to each entry
* @throws UnsupportedOperationException if the {@code set} operation
* is not supported by this map's entry set iterator.
* @throws ClassCastException if the class of a replacement value
* prevents it from being stored in this map
* @throws NullPointerException if the specified function is null, or the
* specified replacement value is null, and this map does not permit null
* values
* @throws ClassCastException if a replacement value is of an inappropriate
* type for this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if function or a replacement value is null,
* and this map does not permit null keys or values
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws IllegalArgumentException if some property of a replacement value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ConcurrentModificationException if an entry is found to be
* removed during iteration
* @since 1.8
*/
default
void
replaceAll
(
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
function
)
{
Objects
.
requireNonNull
(
function
);
for
(
Map
.
Entry
<
K
,
V
>
entry
:
entrySet
())
{
K
k
;
V
v
;
try
{
k
=
entry
.
getKey
();
v
=
entry
.
getValue
();
}
catch
(
IllegalStateException
ise
)
{
throw
new
ConcurrentModificationException
(
ise
);
}
entry
.
setValue
(
function
.
apply
(
k
,
v
));
}
}
/**
* If the specified key is not already associated with a value (or is mapped
* to {@code null}) associates it with the given value and returns
* {@code null}, else returns the current value.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec
* The default implementation is equivalent to, for this {@code
* map}:
*
* <pre> {@code
* if (map.get(key) == null)
* return map.put(key, value);
* else
* return map.get(key);
* }</pre>
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
* {@code 1} if there was no mapping for the key.
* (A {@code null} return can also indicate that the map
* previously associated {@code null} with the key,
* if the implementation supports null values.)
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key or value is null,
* and this map does not permit null keys or values
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ConcurrentModificationException if a modification of the map is
* detected during insertion of the value.
* @since 1.8
*/
default
V
putIfAbsent
(
K
key
,
V
value
)
{
V
v
=
get
(
key
);
if
(
v
==
null
)
{
if
(
put
(
key
,
value
)
!=
null
)
{
throw
new
ConcurrentModificationException
();
}
}
return
v
;
}
/**
* Removes the entry for the specified key only if it is currently
* mapped to the specified value.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec
* The default implementation is equivalent to, for this {@code map}:
*
* <pre> {@code
* if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
* map.remove(key);
* return true;
* } else
* return false;
* }</pre>
*
* @param key key with which the specified value is associated
* @param value value expected to be associated with the specified key
* @return {@code true} if the value was removed
* @throws UnsupportedOperationException if the {@code remove} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key or value is null,
* and this map does not permit null keys or values
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @since 1.8
*/
default
boolean
remove
(
Object
key
,
Object
value
)
{
Object
curValue
=
get
(
key
);
if
(!
Objects
.
equals
(
curValue
,
value
)
||
(
curValue
==
null
&&
!
containsKey
(
key
)))
{
return
false
;
}
remove
(
key
);
return
true
;
}
/**
* Replaces the entry for the specified key only if currently
* mapped to the specified value.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec
* The default implementation is equivalent to, for this {@code map}:
*
* <pre> {@code
* if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
* map.put(key, newValue);
* return true;
* } else
* return false;
* }</pre>
*
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
* @return {@code true} if the value was replaced
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of a specified key or value
* prevents it from being stored in this map
* @throws NullPointerException if a specified key or value is null,
* and this map does not permit null keys or values
* @throws IllegalArgumentException if some property of a specified key
* or value prevents it from being stored in this map
* @since 1.8
*/
default
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
Object
curValue
=
get
(
key
);
if
(!
Objects
.
equals
(
curValue
,
oldValue
)
||
(
curValue
==
null
&&
!
containsKey
(
key
)))
{
return
false
;
}
put
(
key
,
newValue
);
return
true
;
}
/**
* Replaces the entry for the specified key only if it is
* currently mapped to some value.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties.
*
* @implSpec
* The default implementation is equivalent to, for this {@code map}:
*
* <pre> {@code
* if (map.containsKey(key)) {
* return map.put(key, value);
* } else
* return null;
* }</pre>
*
* @param key key with which the specified value is associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
* {@code null} if there was no mapping for the key.
* (A {@code null} return can also indicate that the map
* previously associated {@code null} with the key,
* if the implementation supports null values.)
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key or value is null,
* and this map does not permit null keys or values
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
* @since 1.8
*/
default
V
replace
(
K
key
,
V
value
)
{
return
containsKey
(
key
)
?
put
(
key
,
value
)
:
null
;
}
/**
* If the specified key is not already associated with a value (or
* is mapped to {@code null}), attempts to compute its value using
* the given mapping function and enters it into this map unless
* {@code null}.
*
* <p>If the function returns {@code null} no mapping is recorded. If
* the function itself throws an (unchecked) exception, the
* exception is rethrown, and no mapping is recorded. The most
* common usage is to construct a new object serving as an initial
* mapped value or memoized result, as in:
*
* <pre> {@code
* map.computeIfAbsent(key, k -> new Value(f(k)));
* }</pre>
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
* present. Any class that permits null values must document
* whether and how this method distinguishes absence from null mappings.
*
* @implSpec
* The default implementation is equivalent to the following
* steps for this {@code map}, then returning the current value or
* {@code null} if now absent:
*
* <pre> {@code
* if (map.get(key) == null) {
* V newValue = mappingFunction.apply(key);
* if (newValue != null)
* map.putIfAbsent(key, newValue);
* }
* }</pre>
*
* @param key key with which the specified value is to be associated
* @param mappingFunction the function to compute a value
* @return the current (existing or computed) value associated with
* the specified key, or null if the computed value is null
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
* mappingFunction is null
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @since 1.8
*/
default
V
computeIfAbsent
(
K
key
,
Function
<?
super
K
,
?
extends
V
>
mappingFunction
)
{
V
v
,
newValue
;
return
((
v
=
get
(
key
))
==
null
&&
(
newValue
=
mappingFunction
.
apply
(
key
))
!=
null
&&
(
v
=
putIfAbsent
(
key
,
newValue
))
==
null
)
?
newValue
:
v
;
}
/**
* If the value for the specified key is present and non-null, attempts to
* compute a new mapping given the key and its current mapped value.
*
* <p>If the function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception is
* rethrown, and the current mapping is left unchanged.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
* present. Any class that permits null values must document
* whether and how this method distinguishes absence from null mappings.
*
* @implSpec
* The default implementation is equivalent to performing the
* following steps for this {@code map}, then returning the
* current value or {@code null} if now absent:
*
* <pre> {@code
* if (map.get(key) != null) {
* V oldValue = map.get(key);
* V newValue = remappingFunction.apply(key, oldValue);
* if (newValue != null)
* map.replace(key, oldValue, newValue);
* else
* map.remove(key, oldValue);
* }
* }</pre>
*
* In concurrent contexts, the default implementation may retry
* these steps when multiple threads attempt updates.
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
* remappingFunction is null
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @since 1.8
*/
default
V
computeIfPresent
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
V
oldValue
;
while
((
oldValue
=
get
(
key
))
!=
null
)
{
V
newValue
=
remappingFunction
.
apply
(
key
,
oldValue
);
if
(
newValue
!=
null
)
{
if
(
replace
(
key
,
oldValue
,
newValue
))
return
newValue
;
}
else
if
(
remove
(
key
,
oldValue
))
return
null
;
}
return
oldValue
;
}
/**
* Attempts to compute a mapping for the specified key and its
* current mapped value (or {@code null} if there is no current
* mapping). For example, to either create or append a {@code
* String msg} to a value mapping:
*
* <pre> {@code
* map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
* (Method {@link #merge merge()} is often simpler to use for such purposes.)
*
* <p>If the function returns {@code null}, the mapping is removed (or
* remains absent if initially absent). If the function itself throws an
* (unchecked) exception, the exception is rethrown, and the current mapping
* is left unchanged.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
* present. Any class that permits null values must document
* whether and how this method distinguishes absence from null mappings.
*
* @implSpec
* The default implementation is equivalent to performing the following
* steps for this {@code map}, then returning the current value or
* {@code null} if absent:
*
* <pre> {@code
* V oldValue = map.get(key);
* V newValue = remappingFunction.apply(key, oldValue);
* if (oldValue != null ) {
* if (newValue != null)
* map.replace(key, oldValue, newValue);
* else
* map.remove(key, oldValue);
* } else {
* if (newValue != null)
* map.putIfAbsent(key, newValue);
* else
* return null;
* }
* }</pre>
*
* In concurrent contexts, the default implementation may retry
* these steps when multiple threads attempt updates.
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
* remappingFunction is null
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @since 1.8
*/
default
V
compute
(
K
key
,
BiFunction
<?
super
K
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
V
oldValue
=
get
(
key
);
for
(;;)
{
V
newValue
=
remappingFunction
.
apply
(
key
,
oldValue
);
if
(
oldValue
!=
null
)
{
if
(
newValue
!=
null
)
{
if
(
replace
(
key
,
oldValue
,
newValue
))
return
newValue
;
}
else
if
(
remove
(
key
,
oldValue
))
{
return
null
;
}
oldValue
=
get
(
key
);
}
else
{
if
(
newValue
!=
null
)
{
if
((
oldValue
=
putIfAbsent
(
key
,
newValue
))
==
null
)
return
newValue
;
}
else
{
return
null
;
}
}
}
}
/**
* If the specified key is not already associated with a value or is
* associated with null, associates it with the given value.
* Otherwise, replaces the value with the results of the given
* remapping function, or removes if the result is {@code null}. This
* method may be of use when combining multiple mapped values for a key.
* For example, to either create or append a {@code String msg} to a
* value mapping:
*
* <pre> {@code
* map.merge(key, msg, String::concat)
* }</pre>
*
* <p>If the function returns {@code null}, the mapping is removed (or
* remains absent if initially absent). If the function itself throws an
* (unchecked) exception, the exception is rethrown, and the current mapping
* is left unchanged.
*
* <p>The default implementation makes no guarantees about synchronization
* or atomicity properties of this method. Any implementation providing
* atomicity guarantees must override this method and document its
* concurrency properties. In particular, all implementations of
* subinterface {@link java.util.concurrent.ConcurrentMap} must document
* whether the function is applied once atomically only if the value is not
* present. Any class that permits null values must document
* whether and how this method distinguishes absence from null mappings.
*
* @implSpec
* The default implementation is equivalent to performing the
* following steps for this {@code map}, then returning the
* current value or {@code null} if absent:
*
* <pre> {@code
* V oldValue = map.get(key);
* V newValue = (oldValue == null) ? value :
* remappingFunction.apply(oldValue, value);
* if (newValue == null)
* map.remove(key, oldValue);
* else if (oldValue == null)
* map.putIfAbsent(key, newValue);
* else
* map.replace(key, oldValue, newValue);
* }</pre>
*
* In concurrent contexts, the default implementation may retry
* these steps when multiple threads attempt updates.
*
* @param key key with which the specified value is to be associated
* @param value the value to use if absent
* @param remappingFunction the function to recompute a value if present
* @return the new value associated with the specified key, or null if none
* @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified key is null and
* this map does not support null keys, or the
* remappingFunction is null
* @since 1.8
*/
default
V
merge
(
K
key
,
V
value
,
BiFunction
<?
super
V
,
?
super
V
,
?
extends
V
>
remappingFunction
)
{
V
oldValue
=
get
(
key
);
for
(;;)
{
if
(
oldValue
!=
null
)
{
V
newValue
=
remappingFunction
.
apply
(
oldValue
,
value
);
if
(
newValue
!=
null
)
{
if
(
replace
(
key
,
oldValue
,
newValue
))
return
newValue
;
}
else
if
(
remove
(
key
,
oldValue
))
{
return
null
;
}
oldValue
=
get
(
key
);
}
else
{
if
(
value
==
null
)
{
return
null
;
}
if
((
oldValue
=
putIfAbsent
(
key
,
value
))
==
null
)
{
return
value
;
}
}
}
}
}
}
src/share/classes/java/util/concurrent/ConcurrentMap.java
浏览文件 @
ad59a26e
...
@@ -38,7 +38,7 @@ import java.util.Map;
...
@@ -38,7 +38,7 @@ import java.util.Map;
/**
/**
* A {@link java.util.Map} providing additional atomic
* A {@link java.util.Map} providing additional atomic
*
<tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt>
methods.
*
{@code putIfAbsent}, {@code remove}, and {@code replace}
methods.
*
*
* <p>Memory consistency effects: As with other concurrent
* <p>Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
* collections, actions in a thread prior to placing an object into a
...
@@ -57,6 +57,21 @@ import java.util.Map;
...
@@ -57,6 +57,21 @@ import java.util.Map;
* @param <V> the type of mapped values
* @param <V> the type of mapped values
*/
*/
public
interface
ConcurrentMap
<
K
,
V
>
extends
Map
<
K
,
V
>
{
public
interface
ConcurrentMap
<
K
,
V
>
extends
Map
<
K
,
V
>
{
/**
* {@inheritDoc}
*
* @implNote This implementation assumes that the ConcurrentMap cannot
* contain null values and get() returning null unambiguously means the key
* is absent. Implementations which support null values must override this
* default implementation.
*/
@Override
default
V
getOrDefault
(
Object
key
,
V
defaultValue
)
{
V
v
;
return
((
v
=
get
(
key
))
!=
null
)
?
v
:
defaultValue
;
}
/**
/**
* If the specified key is not already associated
* If the specified key is not already associated
* with a value, associate it with the given value.
* with a value, associate it with the given value.
...
@@ -91,7 +106,7 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
...
@@ -91,7 +106,7 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* Removes the entry for a key only if currently mapped to a given value.
* Removes the entry for a key only if currently mapped to a given value.
* This is equivalent to
* This is equivalent to
* <pre> {@code
* <pre> {@code
* if (map.containsKey(key) &&
map.get(key).equals(
value)) {
* if (map.containsKey(key) &&
Objects.equals(map.get(key),
value)) {
* map.remove(key);
* map.remove(key);
* return true;
* return true;
* } else
* } else
...
@@ -101,8 +116,8 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
...
@@ -101,8 +116,8 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
*
*
* @param key key with which the specified value is associated
* @param key key with which the specified value is associated
* @param value value expected to be associated with the specified key
* @param value value expected to be associated with the specified key
* @return
<tt>true</tt>
if the value was removed
* @return
{@code true}
if the value was removed
* @throws UnsupportedOperationException if the
<tt>remove</tt>
operation
* @throws UnsupportedOperationException if the
{@code remove}
operation
* is not supported by this map
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
* type for this map
...
@@ -117,7 +132,7 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
...
@@ -117,7 +132,7 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* Replaces the entry for a key only if currently mapped to a given value.
* Replaces the entry for a key only if currently mapped to a given value.
* This is equivalent to
* This is equivalent to
* <pre> {@code
* <pre> {@code
* if (map.containsKey(key) &&
map.get(key).equals(
oldValue)) {
* if (map.containsKey(key) &&
Objects.equals(map.get(key),
oldValue)) {
* map.put(key, newValue);
* map.put(key, newValue);
* return true;
* return true;
* } else
* } else
...
@@ -128,8 +143,8 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
...
@@ -128,8 +143,8 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* @param key key with which the specified value is associated
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
* @param newValue value to be associated with the specified key
* @return
<tt>true</tt>
if the value was replaced
* @return
{@code true}
if the value was replaced
* @throws UnsupportedOperationException if the
<tt>put</tt>
operation
* @throws UnsupportedOperationException if the
{@code put}
operation
* is not supported by this map
* is not supported by this map
* @throws ClassCastException if the class of a specified key or value
* @throws ClassCastException if the class of a specified key or value
* prevents it from being stored in this map
* prevents it from being stored in this map
...
@@ -154,11 +169,11 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
...
@@ -154,11 +169,11 @@ public interface ConcurrentMap<K, V> extends Map<K, V> {
* @param key key with which the specified value is associated
* @param key key with which the specified value is associated
* @param value value to be associated with the specified key
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
* @return the previous value associated with the specified key, or
*
<tt>null</tt>
if there was no mapping for the key.
*
{@code null}
if there was no mapping for the key.
* (A
<tt>null</tt>
return can also indicate that the map
* (A
{@code null}
return can also indicate that the map
* previously associated
<tt>null</tt>
with the key,
* previously associated
{@code null}
with the key,
* if the implementation supports null values.)
* if the implementation supports null values.)
* @throws UnsupportedOperationException if the
<tt>put</tt>
operation
* @throws UnsupportedOperationException if the
{@code put}
operation
* is not supported by this map
* is not supported by this map
* @throws ClassCastException if the class of the specified key or value
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* prevents it from being stored in this map
...
...
test/java/util/Map/Defaults.java
0 → 100644
浏览文件 @
ad59a26e
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8010122 8004518
* @summary Test Map default methods
* @author Mike Duigou
* @run testng Defaults
*/
import
java.util.AbstractMap
;
import
java.util.AbstractSet
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.EnumMap
;
import
java.util.HashMap
;
import
java.util.Hashtable
;
import
java.util.IdentityHashMap
;
import
java.util.Iterator
;
import
java.util.LinkedHashMap
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.Set
;
import
java.util.WeakHashMap
;
import
java.util.concurrent.ConcurrentMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentSkipListMap
;
import
java.util.function.Supplier
;
import
org.testng.annotations.Test
;
import
org.testng.annotations.DataProvider
;
import
static
org
.
testng
.
Assert
.
fail
;
import
static
org
.
testng
.
Assert
.
assertEquals
;
import
static
org
.
testng
.
Assert
.
assertTrue
;
import
static
org
.
testng
.
Assert
.
assertFalse
;
import
static
org
.
testng
.
Assert
.
assertNull
;
import
static
org
.
testng
.
Assert
.
assertSame
;
public
class
Defaults
{
@Test
(
dataProvider
=
"Nulls Map<IntegerEnum,String>"
)
public
void
testGetOrDefaultNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertSame
(
map
.
get
(
null
),
map
.
getOrDefault
(
null
,
EXTRA_VALUE
),
"values should match"
);
}
@Test
(
dataProvider
=
"Map<IntegerEnum,String>"
)
public
void
testGetOrDefault
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]),
"expected key missing"
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
map
.
getOrDefault
(
KEYS
[
1
],
EXTRA_VALUE
),
"values should match"
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
),
"expected absent key"
);
assertSame
(
map
.
getOrDefault
(
EXTRA_KEY
,
EXTRA_VALUE
),
EXTRA_VALUE
,
"value not returned as default"
);
assertNull
(
map
.
getOrDefault
(
EXTRA_KEY
,
null
),
"null not returned as default"
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testPutIfAbsentNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertNull
(
map
.
putIfAbsent
(
null
,
EXTRA_VALUE
),
"previous not null"
);
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
"unexpected value"
);
assertSame
(
map
.
putIfAbsent
(
null
,
null
),
EXTRA_VALUE
,
"previous not expected value"
);
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
"unexpected value"
);
assertSame
(
map
.
remove
(
null
),
EXTRA_VALUE
,
"removed unexpected value"
);
assertFalse
(
map
.
containsKey
(
null
),
description
+
": key present after remove"
);
assertNull
(
map
.
putIfAbsent
(
null
,
null
),
"previous not null"
);
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertNull
(
map
.
putIfAbsent
(
null
,
EXTRA_VALUE
),
"previous not null"
);
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
"value not expected"
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testPutIfAbsent
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
expected
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
expected
||
expected
==
VALUES
[
1
]);
assertSame
(
map
.
putIfAbsent
(
KEYS
[
1
],
EXTRA_VALUE
),
expected
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
expected
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
putIfAbsent
(
EXTRA_KEY
,
EXTRA_VALUE
),
null
);
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"Nulls Map<IntegerEnum,String>"
)
public
void
testForEach
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
IntegerEnum
[]
EACH_KEY
=
new
IntegerEnum
[
map
.
size
()];
map
.
forEach
((
k
,
v
)
->
{
int
idx
=
(
null
==
k
)
?
0
:
k
.
ordinal
();
// substitute for index.
assertNull
(
EACH_KEY
[
idx
]);
EACH_KEY
[
idx
]
=
(
idx
==
0
)
?
KEYS
[
0
]
:
k
;
// substitute for comparison.
assertSame
(
v
,
map
.
get
(
k
));
});
assertEquals
(
KEYS
,
EACH_KEY
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
static
void
testRemoveNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertFalse
(
map
.
remove
(
null
,
EXTRA_VALUE
),
description
);
assertTrue
(
map
.
containsKey
(
null
));
assertNull
(
map
.
get
(
null
));
assertTrue
(
map
.
remove
(
null
,
null
));
assertFalse
(
map
.
containsKey
(
null
));
assertNull
(
map
.
get
(
null
));
assertFalse
(
map
.
remove
(
null
,
null
));
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
static
void
testRemove
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
expected
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
expected
||
expected
==
VALUES
[
1
]);
assertFalse
(
map
.
remove
(
KEYS
[
1
],
EXTRA_VALUE
),
description
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
expected
);
assertTrue
(
map
.
remove
(
KEYS
[
1
],
expected
));
assertNull
(
map
.
get
(
KEYS
[
1
]));
assertFalse
(
map
.
remove
(
KEYS
[
1
],
expected
));
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertFalse
(
map
.
remove
(
EXTRA_KEY
,
EXTRA_VALUE
));
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testReplaceKVNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertSame
(
map
.
replace
(
null
,
EXTRA_VALUE
),
null
);
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testReplaceKV
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
expected
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
expected
||
expected
==
VALUES
[
1
]);
assertSame
(
map
.
replace
(
KEYS
[
1
],
EXTRA_VALUE
),
expected
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
EXTRA_VALUE
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertNull
(
map
.
replace
(
EXTRA_KEY
,
EXTRA_VALUE
));
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertNull
(
map
.
get
(
EXTRA_KEY
));
assertNull
(
map
.
put
(
EXTRA_KEY
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
assertSame
(
map
.
replace
(
EXTRA_KEY
,
(
String
)
expected
),
EXTRA_VALUE
);
assertSame
(
map
.
get
(
EXTRA_KEY
),
expected
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testReplaceKVVNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertFalse
(
map
.
replace
(
null
,
EXTRA_VALUE
,
EXTRA_VALUE
));
assertNull
(
map
.
get
(
null
));
assertTrue
(
map
.
replace
(
null
,
null
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
);
assertTrue
(
map
.
replace
(
null
,
EXTRA_VALUE
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testReplaceKVV
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
expected
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
expected
||
expected
==
VALUES
[
1
]);
assertFalse
(
map
.
replace
(
KEYS
[
1
],
EXTRA_VALUE
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
KEYS
[
1
]),
expected
);
assertTrue
(
map
.
replace
(
KEYS
[
1
],
(
String
)
expected
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
KEYS
[
1
]),
EXTRA_VALUE
);
assertTrue
(
map
.
replace
(
KEYS
[
1
],
EXTRA_VALUE
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
KEYS
[
1
]),
EXTRA_VALUE
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertFalse
(
map
.
replace
(
EXTRA_KEY
,
EXTRA_VALUE
,
EXTRA_VALUE
));
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertNull
(
map
.
get
(
EXTRA_KEY
));
assertNull
(
map
.
put
(
EXTRA_KEY
,
EXTRA_VALUE
));
assertTrue
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
assertTrue
(
map
.
replace
(
EXTRA_KEY
,
EXTRA_VALUE
,
EXTRA_VALUE
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testComputeIfAbsentNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertSame
(
map
.
computeIfAbsent
(
null
,
(
k
)
->
EXTRA_VALUE
),
EXTRA_VALUE
,
description
);
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
description
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testComputeIfAbsent
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
expected
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
expected
||
expected
==
VALUES
[
1
],
description
+
String
.
valueOf
(
expected
));
expected
=
(
null
==
expected
)
?
EXTRA_VALUE
:
expected
;
assertSame
(
map
.
computeIfAbsent
(
KEYS
[
1
],
(
k
)
->
EXTRA_VALUE
),
expected
,
description
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
expected
,
description
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
computeIfAbsent
(
EXTRA_KEY
,
(
k
)
->
EXTRA_VALUE
),
EXTRA_VALUE
);
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testComputeIfPresentNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
));
assertNull
(
map
.
get
(
null
));
assertSame
(
map
.
computeIfPresent
(
null
,
(
k
,
v
)
->
{
fail
();
return
EXTRA_VALUE
;
}),
null
,
description
);
assertTrue
(
map
.
containsKey
(
null
));
assertSame
(
map
.
get
(
null
),
null
,
description
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testComputeIfPresent
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
value
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
value
||
value
==
VALUES
[
1
],
description
+
String
.
valueOf
(
value
));
Object
expected
=
(
null
==
value
)
?
null
:
EXTRA_VALUE
;
assertSame
(
map
.
computeIfPresent
(
KEYS
[
1
],
(
k
,
v
)
->
{
assertSame
(
v
,
value
);
return
EXTRA_VALUE
;
}),
expected
,
description
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
expected
,
description
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
computeIfPresent
(
EXTRA_KEY
,
(
k
,
v
)
->
{
fail
();
return
EXTRA_VALUE
;
}),
null
);
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
null
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testComputeNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertSame
(
map
.
compute
(
null
,
(
k
,
v
)
->
{
assertSame
(
k
,
null
);
assertNull
(
v
);
return
EXTRA_VALUE
;
}),
EXTRA_VALUE
,
description
);
assertTrue
(
map
.
containsKey
(
null
));
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
description
);
assertSame
(
map
.
remove
(
null
),
EXTRA_VALUE
,
"removed value not expected"
);
assertFalse
(
map
.
containsKey
(
null
),
"null key present"
);
assertSame
(
map
.
compute
(
null
,
(
k
,
v
)
->
{
assertSame
(
k
,
null
);
assertNull
(
v
);
return
null
;
}),
null
,
description
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testCompute
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
value
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
value
||
value
==
VALUES
[
1
],
description
+
String
.
valueOf
(
value
));
assertSame
(
map
.
compute
(
KEYS
[
1
],
(
k
,
v
)
->
{
assertSame
(
k
,
KEYS
[
1
]);
assertSame
(
v
,
value
);
return
EXTRA_VALUE
;
}),
EXTRA_VALUE
,
description
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
EXTRA_VALUE
,
description
);
assertNull
(
map
.
compute
(
KEYS
[
1
],
(
k
,
v
)
->
{
assertSame
(
v
,
EXTRA_VALUE
);
return
null
;
}),
description
);
assertFalse
(
map
.
containsKey
(
KEYS
[
1
]));
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
compute
(
EXTRA_KEY
,
(
k
,
v
)
->
{
assertNull
(
v
);
return
EXTRA_VALUE
;
}),
EXTRA_VALUE
);
assertTrue
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
}
@Test
(
dataProvider
=
"R/W Nulls Map<IntegerEnum,String>"
)
public
void
testMergeNulls
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
null
),
"null key absent"
);
assertNull
(
map
.
get
(
null
),
"value not null"
);
assertSame
(
map
.
merge
(
null
,
EXTRA_VALUE
,
(
v
,
vv
)
->
{
assertNull
(
v
);
assertSame
(
vv
,
EXTRA_VALUE
);
return
vv
;
}),
EXTRA_VALUE
,
description
);
assertTrue
(
map
.
containsKey
(
null
));
assertSame
(
map
.
get
(
null
),
EXTRA_VALUE
,
description
);
}
@Test
(
dataProvider
=
"R/W Map<IntegerEnum,String>"
)
public
void
testMerge
(
String
description
,
Map
<
IntegerEnum
,
String
>
map
)
{
assertTrue
(
map
.
containsKey
(
KEYS
[
1
]));
Object
value
=
map
.
get
(
KEYS
[
1
]);
assertTrue
(
null
==
value
||
value
==
VALUES
[
1
],
description
+
String
.
valueOf
(
value
));
assertSame
(
map
.
merge
(
KEYS
[
1
],
EXTRA_VALUE
,
(
v
,
vv
)
->
{
assertSame
(
v
,
value
);
assertSame
(
vv
,
EXTRA_VALUE
);
return
vv
;
}),
EXTRA_VALUE
,
description
);
assertSame
(
map
.
get
(
KEYS
[
1
]),
EXTRA_VALUE
,
description
);
assertNull
(
map
.
merge
(
KEYS
[
1
],
EXTRA_VALUE
,
(
v
,
vv
)
->
{
assertSame
(
v
,
EXTRA_VALUE
);
assertSame
(
vv
,
EXTRA_VALUE
);
return
null
;
}),
description
);
assertFalse
(
map
.
containsKey
(
KEYS
[
1
]));
assertFalse
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
merge
(
EXTRA_KEY
,
EXTRA_VALUE
,
(
v
,
vv
)
->
{
assertNull
(
v
);
assertSame
(
vv
,
EXTRA_VALUE
);
return
EXTRA_VALUE
;
}),
EXTRA_VALUE
);
assertTrue
(
map
.
containsKey
(
EXTRA_KEY
));
assertSame
(
map
.
get
(
EXTRA_KEY
),
EXTRA_VALUE
);
}
enum
IntegerEnum
{
e0
,
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
,
e10
,
e11
,
e12
,
e13
,
e14
,
e15
,
e16
,
e17
,
e18
,
e19
,
e20
,
e21
,
e22
,
e23
,
e24
,
e25
,
e26
,
e27
,
e28
,
e29
,
e30
,
e31
,
e32
,
e33
,
e34
,
e35
,
e36
,
e37
,
e38
,
e39
,
e40
,
e41
,
e42
,
e43
,
e44
,
e45
,
e46
,
e47
,
e48
,
e49
,
e50
,
e51
,
e52
,
e53
,
e54
,
e55
,
e56
,
e57
,
e58
,
e59
,
e60
,
e61
,
e62
,
e63
,
e64
,
e65
,
e66
,
e67
,
e68
,
e69
,
e70
,
e71
,
e72
,
e73
,
e74
,
e75
,
e76
,
e77
,
e78
,
e79
,
e80
,
e81
,
e82
,
e83
,
e84
,
e85
,
e86
,
e87
,
e88
,
e89
,
e90
,
e91
,
e92
,
e93
,
e94
,
e95
,
e96
,
e97
,
e98
,
e99
,
EXTRA_KEY
;
public
static
final
int
SIZE
=
values
().
length
;
};
private
static
final
int
TEST_SIZE
=
IntegerEnum
.
SIZE
-
1
;
/**
* Realized keys ensure that there is always a hard ref to all test objects.
*/
private
static
final
IntegerEnum
[]
KEYS
=
new
IntegerEnum
[
TEST_SIZE
];
/**
* Realized values ensure that there is always a hard ref to all test
* objects.
*/
private
static
final
String
[]
VALUES
=
new
String
[
TEST_SIZE
];
static
{
IntegerEnum
[]
keys
=
IntegerEnum
.
values
();
for
(
int
each
=
0
;
each
<
TEST_SIZE
;
each
++)
{
KEYS
[
each
]
=
keys
[
each
];
VALUES
[
each
]
=
String
.
valueOf
(
each
);
}
}
private
static
final
IntegerEnum
EXTRA_KEY
=
IntegerEnum
.
EXTRA_KEY
;
private
static
final
String
EXTRA_VALUE
=
String
.
valueOf
(
TEST_SIZE
);
@DataProvider
(
name
=
"Map<IntegerEnum,String>"
,
parallel
=
true
)
public
static
Iterator
<
Object
[]>
allNullsMapProvider
()
{
return
makeAllMaps
().
iterator
();
}
@DataProvider
(
name
=
"Nulls Map<IntegerEnum,String>"
,
parallel
=
true
)
public
static
Iterator
<
Object
[]>
allMapProvider
()
{
return
makeRWMaps
(
true
).
iterator
();
}
@DataProvider
(
name
=
"R/W Map<IntegerEnum,String>"
,
parallel
=
true
)
public
static
Iterator
<
Object
[]>
rwMapProvider
()
{
return
makeRWMapsNoNulls
().
iterator
();
}
@DataProvider
(
name
=
"R/W Nulls Map<IntegerEnum,String>"
,
parallel
=
true
)
public
static
Iterator
<
Object
[]>
rwNullsMapProvider
()
{
return
makeRWMaps
(
true
).
iterator
();
}
private
static
Collection
<
Object
[]>
makeAllMapsNoNulls
()
{
Collection
<
Object
[]>
all
=
new
ArrayList
<>();
all
.
addAll
(
makeRWMaps
(
false
));
all
.
addAll
(
makeRWNoNullsMaps
());
all
.
addAll
(
makeROMaps
(
false
));
return
all
;
}
private
static
Collection
<
Object
[]>
makeRWMapsNoNulls
()
{
Collection
<
Object
[]>
all
=
new
ArrayList
<>();
all
.
addAll
(
makeRWMaps
(
false
));
all
.
addAll
(
makeRWNoNullsMaps
());
return
all
;
}
private
static
Collection
<
Object
[]>
makeAllMaps
()
{
Collection
<
Object
[]>
all
=
new
ArrayList
<>();
all
.
addAll
(
makeROMaps
(
false
));
all
.
addAll
(
makeRWMaps
(
false
));
all
.
addAll
(
makeRWNoNullsMaps
());
all
.
addAll
(
makeRWMaps
(
true
));
all
.
addAll
(
makeROMaps
(
true
));
return
all
;
}
private
static
Collection
<
Object
[]>
makeAllRWMaps
()
{
Collection
<
Object
[]>
all
=
new
ArrayList
<>();
all
.
addAll
(
makeRWMaps
(
false
));
all
.
addAll
(
makeRWNoNullsMaps
());
all
.
addAll
(
makeRWMaps
(
true
));
return
all
;
}
private
static
Collection
<
Object
[]>
makeRWMaps
(
boolean
nulls
)
{
return
Arrays
.
asList
(
new
Object
[]{
"HashMap"
,
makeMap
(
HashMap:
:
new
,
nulls
)},
new
Object
[]{
"IdentityHashMap"
,
makeMap
(
IdentityHashMap:
:
new
,
nulls
)},
new
Object
[]{
"LinkedHashMap"
,
makeMap
(
LinkedHashMap:
:
new
,
nulls
)},
new
Object
[]{
"WeakHashMap"
,
makeMap
(
WeakHashMap:
:
new
,
nulls
)},
new
Object
[]{
"Collections.checkedMap(HashMap)"
,
Collections
.
checkedMap
(
makeMap
(
HashMap:
:
new
,
nulls
),
IntegerEnum
.
class
,
String
.
class
)},
new
Object
[]{
"Collections.synchronizedMap(HashMap)"
,
Collections
.
synchronizedMap
(
makeMap
(
HashMap:
:
new
,
nulls
))},
new
Object
[]{
"ExtendsAbstractMap"
,
makeMap
(
ExtendsAbstractMap:
:
new
,
nulls
)});
}
private
static
Collection
<
Object
[]>
makeRWNoNullsMaps
()
{
return
Arrays
.
asList
(
// null hostile
new
Object
[]{
"EnumMap"
,
makeMap
(()
->
new
EnumMap
(
IntegerEnum
.
class
),
false
)},
new
Object
[]{
"Hashtable"
,
makeMap
(
Hashtable:
:
new
,
false
)},
new
Object
[]{
"TreeMap"
,
makeMap
(
TreeMap:
:
new
,
false
)},
new
Object
[]{
"ConcurrentHashMap"
,
makeMap
(
ConcurrentHashMap:
:
new
,
false
)},
new
Object
[]{
"ConcurrentSkipListMap"
,
makeMap
(
ConcurrentSkipListMap:
:
new
,
false
)},
new
Object
[]{
"Collections.checkedMap(ConcurrentHashMap)"
,
Collections
.
checkedMap
(
makeMap
(
ConcurrentHashMap:
:
new
,
false
),
IntegerEnum
.
class
,
String
.
class
)},
new
Object
[]{
"Collections.synchronizedMap(EnumMap)"
,
Collections
.
synchronizedMap
(
makeMap
(()
->
new
EnumMap
(
IntegerEnum
.
class
),
false
))},
new
Object
[]{
"ImplementsConcurrentMap"
,
makeMap
(
ImplementsConcurrentMap:
:
new
,
false
)});
}
private
static
Collection
<
Object
[]>
makeROMaps
(
boolean
nulls
)
{
return
Arrays
.
asList
(
new
Object
[][]{
new
Object
[]{
"Collections.unmodifiableMap(HashMap)"
,
Collections
.
unmodifiableMap
(
makeMap
(
HashMap:
:
new
,
nulls
))}
});
}
private
static
Map
<
IntegerEnum
,
String
>
makeMap
(
Supplier
<
Map
<
IntegerEnum
,
String
>>
supplier
,
boolean
nulls
)
{
Map
<
IntegerEnum
,
String
>
result
=
supplier
.
get
();
for
(
int
each
=
0
;
each
<
TEST_SIZE
;
each
++)
{
if
(
nulls
)
{
result
.
put
((
each
==
0
)
?
null
:
KEYS
[
each
],
null
);
}
else
{
result
.
put
(
KEYS
[
each
],
VALUES
[
each
]);
}
}
return
result
;
}
public
interface
Thrower
<
T
extends
Throwable
>
{
public
void
run
()
throws
T
;
}
public
static
<
T
extends
Throwable
>
void
assertThrows
(
Thrower
<
T
>
thrower
,
Class
<
T
>
throwable
)
{
assertThrows
(
thrower
,
throwable
,
null
);
}
public
static
<
T
extends
Throwable
>
void
assertThrows
(
Thrower
<
T
>
thrower
,
Class
<
T
>
throwable
,
String
message
)
{
Throwable
result
;
try
{
thrower
.
run
();
result
=
null
;
}
catch
(
Throwable
caught
)
{
result
=
caught
;
}
assertInstance
(
result
,
throwable
,
(
null
!=
message
)
?
message
:
"Failed to throw "
+
throwable
.
getCanonicalName
());
}
public
static
<
T
>
void
assertInstance
(
T
actual
,
Class
<?
extends
T
>
expected
)
{
assertInstance
(
expected
.
isInstance
(
actual
),
null
);
}
public
static
<
T
>
void
assertInstance
(
T
actual
,
Class
<?
extends
T
>
expected
,
String
message
)
{
assertTrue
(
expected
.
isInstance
(
actual
),
message
);
}
/**
* A simple mutable map implementation that provides only default
* implementations of all methods. ie. none of the Map interface default
* methods have overridden implementations.
*
* @param <K> Type of keys
* @param <V> Type of values
*/
public
static
class
ExtendsAbstractMap
<
M
extends
Map
<
K
,
V
>,
K
,
V
>
extends
AbstractMap
<
K
,
V
>
{
protected
final
M
map
;
public
ExtendsAbstractMap
()
{
this
(
(
M
)
new
HashMap
<
K
,
V
>());
}
protected
ExtendsAbstractMap
(
M
map
)
{
this
.
map
=
map
;
}
public
Set
<
Map
.
Entry
<
K
,
V
>>
entrySet
()
{
return
new
AbstractSet
<
Map
.
Entry
<
K
,
V
>>()
{
public
int
size
()
{
return
map
.
size
();
}
public
Iterator
<
Map
.
Entry
<
K
,
V
>>
iterator
()
{
final
Iterator
<
Map
.
Entry
<
K
,
V
>>
source
=
map
.
entrySet
().
iterator
();
return
new
Iterator
<
Map
.
Entry
<
K
,
V
>>()
{
public
boolean
hasNext
()
{
return
source
.
hasNext
();
}
public
Map
.
Entry
<
K
,
V
>
next
()
{
return
source
.
next
();
}
public
void
remove
()
{
source
.
remove
();
}
};
}
public
boolean
add
(
Map
.
Entry
<
K
,
V
>
e
)
{
return
map
.
entrySet
().
add
(
e
);
}
};
}
public
V
put
(
K
key
,
V
value
)
{
return
map
.
put
(
key
,
value
);
}
}
/**
* A simple mutable concurrent map implementation that provides only default
* implementations of all methods. ie. none of the ConcurrentMap interface
* default methods have overridden implementations.
*
* @param <K> Type of keys
* @param <V> Type of values
*/
public
static
class
ImplementsConcurrentMap
<
K
,
V
>
extends
ExtendsAbstractMap
<
ConcurrentMap
<
K
,
V
>,
K
,
V
>
implements
ConcurrentMap
<
K
,
V
>
{
public
ImplementsConcurrentMap
()
{
super
(
new
ConcurrentHashMap
<
K
,
V
>());
}
// ConcurrentMap reabstracts these methods
public
V
replace
(
K
k
,
V
v
)
{
return
map
.
replace
(
k
,
v
);
};
public
boolean
replace
(
K
k
,
V
v
,
V
vv
)
{
return
map
.
replace
(
k
,
v
,
vv
);
};
public
boolean
remove
(
Object
k
,
Object
v
)
{
return
map
.
remove
(
k
,
v
);
}
public
V
putIfAbsent
(
K
k
,
V
v
)
{
return
map
.
putIfAbsent
(
k
,
v
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录