Map接口总结(如何使用默认方法)
Map接口总结(如何使用默认方法)
Map的基本使用
默认方法的问题,有什么坑
常用的默认方法应用场景
基本操作
get
put(区别:Collection接口中添加为set)
putAll
remove
containsKey
containsValue
size
clear
遍历操作
keySet()
values()
entrySet()
实现规约
以下两个方法提示实现类需要重写用来比较相等的方法。
equals
hashcode
以下两个方法是标准库的约定,但是Java中接口不支持定义构造器约束,只能保证标准库中都实现了这两个方法。
构造器(空参数)
构造器(Map other)
default方法
排序在前的方法较为常用。
默认方法是为了在标准库中添加默认支持函数式方法,同时也不必修改现有的类,这样做虽然有一定的好处,但是实际上在子类中使用default方法还是极有可能出错的,因为一个default方法无法满足所有的子类,也不可能满足。如果随意使用default方法,可能破坏了原有子类的一致性,产生意想不到的问题。
在标准库中,除了并发相关类,比如ConcurrentHashMap等,一般没有问题。
但是在其他类库的实现类中使用一定要慎之又慎,比如使用一个老版本的Map子类。
引入default方法破坏了前向兼容性,容易产生运行时异常。
V getOrDefault(Object key, V defaultValue)常用,获取值或者默认值,可类比Optional.orElse。以下是先做判断,后计算的(if true)
V putIfAbsent(K key, V value)V replace(K key, V value)感觉叫putIfPresent更好boolean replace(K key, V oldValue, V newValue)boolean remove(Object key, Object value)如果匹配的话,remove以下四个方法为一组,都是对entry(k, v)的更新,只是条件不一样。
V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction)
// 如果没有entry则更新
// 返回值为value,可以用于后续操作
// 常用于MultiMap,如下面一句话表示把用户添加到用户组里
map.computeIfAbsent(userGroup, k -> new HashMap<User>()).add(user);
V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction)
// 如果有entry则更新
V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction)
// 不常用,因为如果不包含entry则可能抛出空指针异常
// 可以理解为同时支持上面两个方法,但是我们一般都需要对是否包含entry进行判断,所以不常用。
// compute方法也可以实现merge这样的规约操作,既然如此,在需要规约操作时,我们为什么不用merge呢。
// v 可能为空指针,程序员极有可能忘记检查,编译器也不能帮助检查。
// 总之,这个compute方法不常用。 // compute进行null判断
map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))
// merge中更简单
map.merge(key, msg, String::concat)
V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction)
// 没有则使用默认值,有则进行类似reduce的操作
// 规约结果为null时,则删除
// 好用
// 常用来计数
map.merge(key, 1, Integer::sum);
void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
// 使用泛型达到了更广的匹配
// 通配符使用原则,使用的对象 (consumer) 使用 super,生成的对象 (provider) 使用 extends。
forEach(BiConsumer<? super K, ? super V> action)!!!经常滥用的方法,不建议使用,action只建议使用简单的逻辑。每回看到别人使用forEach方法都感觉很恶心,这个方法看上去好用,可以传入(k,v)→ ... lambda表达式,但是函数式方法应该尽量不产生副作用,使用函数式方法的目的应该便于理解。然而在项目中经常看到大段的lambda表达式传入,在不便于调试的同时,还不能产生副作用。由于副作用的问题,每回想修改forEach的逻辑时,都必须改为for (Map.Entry<K, V> entry : map.entrySet()),然后再修改逻辑。
包括Collections下的List,Set等都有滥用forEach方法。
以下是我在网上找的一个例子,不知道你看到forEach后啥感觉,我反正是要吐了,况且这还是一段逻辑相对简单的代码。
public static void main(String[] args)
{ // create a HashMap and add some values
HashMap<Integer, String>
map1 = new HashMap<>();
map1.put(1, "Ram");
map1.put(2, "Rohan");
map1.put(3, "Shivam"); HashMap<Integer, String>
map2 = new HashMap<>();
map2.put(1, "Tushar");
map2.put(10, "Satya");
map2.put(12, "Sundar"); // print map details
System.out.println("HashMap1: "
+ map1.toString()); System.out.println("HashMap2: "
+ map2.toString()); // provide value for new key which is absent
// using computeIfAbsent method
map2.forEach(
(key, value)
-> map1.merge(
key,
value,
(v1, v2)
-> v1.equalsIgnoreCase(v2)
? v1
: v1 + ", " + v2)); // print new mapping
System.out.println("New HashMap: " + map1);
}
总之,函数式方法使用的函数应该足够简单,便于理解。
如果使用默认方法可以简化了理解,代码更简洁,而且没有副作用,确保代码兼容性,可以使用默认方法,其他情况下还是老老实实用命令式编程吧。
Map接口总结(如何使用默认方法)的更多相关文章
- JDK8新特性:接口的静态方法和默认方法
在jdk8之前,interface之中可以定义变量和方法,变量必须是public.static.final的,方法必须是public.abstract的.由于这些修饰符都是默认的,所以在JDK8之前, ...
- Java 8——接口中个的默认方法和静态方法
在Java SE 8之前,interface只是事物的抽象,用来定义统一的抽象事物和描述事物的抽象行为和属性. 但是在Java SE 8中,增加了可以在interface中增加默认实现的行为和事物的静 ...
- java8-新特性--(接口的默认方法与静态方法)
Java 8用默认方法与静态方法这两个新概念来扩展接口的声明. public interface Inte{ void method(); default void defaultMethod(){ ...
- Java8新特性第2章(接口默认方法)
在Java中一个接口一旦发布就已经被定型,除非我们能够一次性的更新所有该接口的实现,否者在接口的添加新方法将会破坏现有接口的实现.默认方法就是为了解决这一问题的,这样接口在发布之后依然能够继续演化. ...
- jdk8系列一、jdk8 Lamda表达式语法、接口的默认方法和静态方法、supplier用法
一.简介 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性. 在本文中我们将学习这些新特性,并用实际 ...
- Java8接口中的默认方法
Java8新增特性,可以为接口中添加默认方法,实现这个接口的所有类都会继承这个方法,这样看起来,接口和类的界限就有点不明显了,同时也会带来多继承,菱形问题.这样设计的初衷是什么? 重所周知,java8 ...
- 一文带你认识Java8中接口的默认方法
Java8是Oracle于2014年3月发布的一个重要版本,其API在现存的接口上引入了非常多的新方法. 例如,Java8的List接口新增了sort方法.在Java8之前,则每个实现了List接口的 ...
- 乐字节-Java8核心特性实战-接口默认方法
JAVA8已经发布很久,是自java5(2004年发布)之后Oracle发布的最重要的一个版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性,对于国内外互联网公司来说,Java8是以后技术 ...
- java8新特性- 默认方法 在接口中有具体的实现
案例分析 在java8中在对list循环的时候,我们可以使用forEach这个方法对list进行遍历,具体代码如下demo所示 public static void main(String[] arg ...
- 紧随时代的步伐--Java8特性之接口默认方法
1.关于Java8 自从1996年Sun公司发布Java以来,Java到目前为止已经走过21个年头,每一次的升级,都是Java语言的革新,对时代发展的适应.2014年Oracle发布Java8,而据可 ...
随机推荐
- create-react-app的TS支持以及css模块化
开始: 利用官方脚手架,搭建react工程.参考:https://react.docschina.org/docs/create-a-new-react-app.html. 过程: 1.暴露webpa ...
- ZooKeeper 到底解决了什么问题?
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 目标 ZooKeeper 很流行,有个基本的疑问: Zo ...
- Docker系列教程05-Docker数据卷(Data Volume)学习
引言 在Docker中,容器的数据读写默认发生在容器的存储层,当容器被删除时其上的数据将会丢失.要想实现数据的持久化,需要将数据从宿主机挂载到容器中.目前Docker提供了三种方式将数据从宿主机挂载到 ...
- Golang 实现 Redis(11): RDB 文件解析
RDB 文件使用二进制方式存储 Redis 内存中的数据,具有体积小.加载快的优点.本文主要介绍 RDB 文件的结构和编码方式,并借此探讨二进制编解码和文件处理方式,希望对您有所帮助. 本文基于 RD ...
- .NET 中 GC 的模式与风格
垃圾回收(GC)是托管语言必备的技术之一.GC 的性能是影响托管语言性能的关键.我们的 .NET 既能写桌面程序 (WINFROM , WPF) 又能写 web 程序 (ASP.NET CORE),甚 ...
- [ Module ] 环境变量管理工具 Module 安装和使用
https://www.cnblogs.com/yeungchie/ 1. 工具下载 手动下载 modules-5.1.0 点击下载 wget 下载 wget https://jaist.dl.sou ...
- kvm 虚拟化技术 1.3之kvm克隆以及快照
1.kvm虚拟机克隆 克隆kvm虚拟机 ,克隆前需要提前关机 语法: virt-clone -o 原虚拟机 -n 新虚拟机 -f 新虚拟机镜像存放路径 选项中-o 表示 old ...
- Jenkins安装详解
一.Jenkins是什么 Jenkins是一个独立的开源自动化服务器,可用于自动执行与构建,测试,交付或者部署软件相关的各种任务,是跨平台持续集成和持续交付应用程序,提高工作效率.使用Jenkins不 ...
- 运维:ITIL V3
TIL 简史 在20 世纪80 年代末期,英国商务部(OGC,Office Government Commerce)发布了ITIL .OGC 最初的目标是通过应用IT 来提升政府业务的效率:目标是能够 ...
- [漏洞复现] [Vulhub靶机] Tomcat7+ 弱口令 && 后台getshell漏洞
免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责. 0x00 背景知识 war文件 0x01 漏洞介绍 影响范围:Tomcat 8.0版本 漏洞类型:弱口令 漏洞成因:在tomc ...