Map接口在JDK 8中提供了一些方便的新方法 。 因为我在本文中介绍的Map
方法是作为默认方法实现的,所以Map
接口的所有现有实现都享有默认方法中定义的默认行为,而无需任何新代码。 这篇文章中介绍的JDK 8引入的Map
方法是getOrDefault(Object,V) , putIfAbsent(K,V) ,remove(Object,Object), remove(Object,Object) , replace(K,V)和replace(K ,V,V) 。
演示示例图
在本博文的所有示例中,我将使用以下代码中所示的声明和初始化Map
。 statesAndCapitals
字段是类级别的静态字段。 我特意只包含了美国五十个州中的一小部分,以使阅读更加清晰,并使某些新的JDK 8 Map
默认方法的演示更加容易。
private final static Map statesAndCapitals;static{statesAndCapitals = new HashMap<>();statesAndCapitals.put("Alaska", "Anchorage");statesAndCapitals.put("California", "Sacramento");statesAndCapitals.put("Colorado", "Denver");statesAndCapitals.put("Florida", "Tallahassee");statesAndCapitals.put("Nevada", "Las Vegas");statesAndCapitals.put("New Mexico", "Sante Fe");statesAndCapitals.put("Utah", "Salt Lake City");statesAndCapitals.put("Wyoming", "Cheyenne");}
Map.getOrDefault(Object,V)
Map
的新方法getOrDefault(Object,V)允许调用者在单个语句中指定以获取与提供的键对应的映射值,或者如果找不到与提供的键匹配的返回值,则返回提供的“默认值”键。
下一个代码清单比较了如何在JDK 8之前实现与映射中提供的键相匹配的值的检查,或者如果没有找到匹配项,则使用默认值,以及如何在JDK 8中实现。
/** Demonstrate Map.getOrDefault and compare to pre-JDK 8 approach. The JDK 8* addition of Map.getOrDefault requires fewer lines of code than the* traditional approach and allows the returned value to be assigned to a* "final" variable.*/// pre-JDK 8 approach
String capitalGeorgia = statesAndCapitals.get("Georgia");
if (capitalGeorgia == null)
{capitalGeorgia = "Unknown";
}// JDK 8 approach
final String capitalWisconsin = statesAndCapitals.getOrDefault("Wisconsin", "Unknown");
Apache Commons类DefaultedMap提供的功能类似于新的Map.getOrDefault(Object, V)
方法。 Groovy GDK包括一个与Groovy类似的方法Map.get(Object,Object) ,但是它的行为有些不同,因为如果找不到“ key”,它不仅会返回提供的默认值,而且还会添加带有基础地图的默认值。
Map.putIfAbsent(K,V)
Map
的新方法putIfAbsent(K,V)的 Javadoc公布了等效的默认实现:
The default implementation is equivalent to, for this map:V v = map.get(key);if (v == null)v = map.put(key, value);return v;
另一个代码示例对此进行了说明,该示例将JDK 8之前的方法与JDK 8的方法进行了比较。
/** Demonstrate Map.putIfAbsent and compare to pre-JDK 8 approach. The JDK 8* addition of Map.putIfAbsent requires fewer lines of code than the* traditional approach and allows the returned value to be assigned to a* "final" variable.*/// pre-JDK 8 approach
String capitalMississippi = statesAndCapitals.get("Mississippi");
if (capitalMississippi == null)
{capitalMississippi = statesAndCapitals.put("Mississippi", "Jackson");
}// JDK 8 approach
final String capitalNewYork = statesAndCapitals.putIfAbsent("New York", "Albany");
在StackOverflow线程Java map.get(key)中讨论了在添加putIfAbsent
方法之前在Java空间中的替代解决方案–自动执行put(key)并在key不存在时返回? 。 值得注意的是,在JDK 8之前, ConcurrentMap接口(扩展Map
)已经提供了putIfAbsent(K,V)方法。
Map.remove(Object,Object)
Map
的新删除(对象,对象)方法超出了长可Map.remove(对象)方法来删除一个映射条目仅当所提供的密钥,并提供价值相匹配的地图(一个条目以前使用的版本只寻找要删除的“关键”匹配项)。
此方法的Javadoc注释根据等效的JDK 8之前的Java代码说明了默认方法的实现方式:
对于此映射,默认实现等效于:
if (map.containsKey(key) && Objects.equals(map.get(key), value)) {map.remove(key);return true;} elsereturn false;
下一个代码清单中显示了新方法与JDK 8之前方法的具体比较。
/** Demonstrate Map.remove(Object, Object) and compare to pre-JDK 8 approach.* The JDK 8 addition of Map.remove(Object, Object) requires fewer lines of* code than the traditional approach and allows the returned value to be* assigned to a "final" variable.*/// pre-JDK 8 approach
boolean removed = false;
if ( statesAndCapitals.containsKey("New Mexico")&& Objects.equals(statesAndCapitals.get("New Mexico"), "Sante Fe"))
{statesAndCapitals.remove("New Mexico", "Sante Fe");removed = true;
}// JDK 8 approach
final boolean removedJdk8 = statesAndCapitals.remove("California", "Sacramento");
Map.replace(K,V)
两个新Map
“替换”方法中的第一个方法仅在指定键已经存在且具有某些映射值的情况下,将指定值设置为映射到指定键。 Javadoc注释说明了此默认方法实现的Java等效项:
对于此映射,默认实现等效于:
if (map.containsKey(key)) {return map.put(key, value);} elsereturn null;
接下来显示此新方法与JDK 8之前的方法的比较。
/** Demonstrate Map.replace(K, V) and compare to pre-JDK 8 approach. The JDK 8* addition of replace(K, V) requires fewer lines of code than the traditional* approach and allows the returned value to be assigned to a "final" * variable.*/// pre-JDK 8 approach
String replacedCapitalCity;
if (statesAndCapitals.containsKey("Alaska"))
{replacedCapitalCity = statesAndCapitals.put("Alaska", "Juneau");
}// JDK 8 approach
final String replacedJdk8City = statesAndCapitals.replace("Alaska", "Juneau");
Map.replace(K,V,V)
第二个新添加的Map
“替换”方法在解释哪些现有值被替换时更窄。 尽管刚才介绍的方法将替换映射中可用于指定键的值中的任何值,但是这种接受附加( 第三个 )参数的“替换”方法将仅替换既具有匹配键又具有匹配键的映射条目的值。匹配值。 Javadoc注释显示了默认方法的实现:
The default implementation is equivalent to, for this map:if (map.containsKey(key) && Objects.equals(map.get(key), value)) {map.put(key, newValue);return true;} elsereturn false;
下一个代码清单显示了我与JDK 8之前的方法的比较。
/** Demonstrate Map.replace(K, V, V) and compare to pre-JDK 8 approach. The* JDK 8 addition of replace(K, V, V) requires fewer lines of code than the* traditional approach and allows the returned value to be assigned to a* "final" variable.*/// pre-JDK 8 approach
boolean replaced = false;
if ( statesAndCapitals.containsKey("Nevada")&& Objects.equals(statesAndCapitals.get("Nevada"), "Las Vegas"))
{statesAndCapitals.put("Nevada", "Carson City");replaced = true;
}// JDK 8 approach
final boolean replacedJdk8 = statesAndCapitals.replace("Nevada", "Las Vegas", "Carson City");
观察与结论
从这篇文章中可以得出一些结论。
- 这些新的JDK 8
Map
方法的Javadoc方法非常有用,特别是在描述新方法如何按照JDK 8之前的代码表现时。 我在有关基于JDK 8 Javadoc的API文档的更一般性讨论中讨论了这些方法的Javadoc。 - 正如这些方法的Javadoc注释中的等效Java代码所指示的那样,这些新方法通常在访问映射键和值之前不检查null。 因此,使用Javadoc注释中所示的“等效”代码时,使用这些方法可能会遇到与null相同的问题。 实际上,Javadoc注释通常会警告NullPointerException的可能性,以及与某些
Map
实现允许null以及某些键和值不允许的问题有关的问题。 - 本文中讨论的新
Map
方法是“默认方法”,这意味着Map
实现会自动“继承”这些实现。 - 本文中讨论的新
Map
方法允许使用更简洁的代码。 在我的大多数示例中,它们允许将客户端代码从多个影响状态的语句转换为可以一次性设置局部变量的单个语句。
这篇文章中介绍的新Map
方法并不是开创性的或破天荒的,但它们为许多Java开发人员以前实现了更多详细代码,为其编写了自己的相似方法或为第三方库提供了便利。 JDK 8将这些标准化方法带给了Java大众,而无需自定义实现或第三方框架。 由于默认方法是实现机制,因此即使已经存在了很长时间的Map
实现也突然并自动访问了这些新方法,而无需对实现进行任何代码更改。
翻译自: https://www.javacodegeeks.com/2014/04/handy-new-map-default-methods-in-jdk-8.html