【java9】java9新特性值之集合不可变实例工厂方法

Java9为集合接口List、Set、Map提供了创建不可变实例的工厂方法。这些工厂方法为便利而生,以简单的方式创建这些集合的不可变实例。

Java9之前创建不可变集合

在Java9之前,创建不可变集合通常需要通过其他方式,比如使用Collections.unmodifiableList()Collections.unmodifiableSet()Collections.unmodifiableMap()等方法来包装一个可变集合,使其变为不可变。

package com.morris.java9;

import java.util.*;

/**
 * Java8创建不可变集合
 */
public class Collection8Demo {
    public static void main(String[] args) {
        // 创建不可变List
        List<String> mutableList = new ArrayList<>(Arrays.asList("one", "two", "three"));
        List<String> immutableList = Collections.unmodifiableList(mutableList);
        System.out.println(immutableList);
        mutableList.add("four");
        System.out.println(immutableList);

        // 创建不可变Set
        Set<String> mutableSet = new HashSet<>(Arrays.asList("one", "two", "three"));
        Set<String> immutableSet = Collections.unmodifiableSet(mutableSet);
        System.out.println(immutableSet);

        // 创建不可变Map
        Map<String, Integer> mutableMap = new HashMap<>();
        mutableMap.put("one", 1);
        mutableMap.put("two", 2);
        Map<String, Integer> immutableMap = Collections.unmodifiableMap(mutableMap);
        System.out.println(immutableMap);
    }
}

运行结果如下:

[one, two, three]
[one, two, three, four]
[one, two, three]
{one=1, two=2}

创建可变集合很简单,但是创建不可变集合则先需要创建一个可变集合,然后再使用Collections.unmodifiableXxx来创建不可变集合。为什么会这么复杂?因为不可变集合一旦创建元素是固定的,也就无法使用add/put/remove等方法来修改集合中的元素。

Collections.unmodifiableList()的底层会使用静态代理模式将原来的ArrayList封装为UnmodifiableList类,对UnmodifiableList类的修改操作都会抛出异常,UnmodifiableList类的add/put/remove方法源码如下:

public E set(int index, E element) {
    throw new UnsupportedOperationException();
}
public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
public E remove(int index) {
    throw new UnsupportedOperationException();
}

然而,这种方式仍然依赖于原始的可变集合,如果原始集合被修改,那么这些不可变集合的行为就会变得不可预测。在上面的例子中可以看到对原始集合进行添加元素,不可变集合中的元素也被修改了。

Java9创建不可变集合

在Java9中,为集合接口(List、Set、Map)提供了创建不可变实例的工厂方法,其中最常用的方法是of()。这个方法用于定义三种集合的不可变实例,参数即为不可变实例的所有元素。

package com.morris.java9;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Java9创建不可变集合
 */
public class Collection9Demo {
    public static void main(String[] args) {
        // 创建不可变List
        List<String> immutableList = List.of("one", "two", "three");
        System.out.println(immutableList);

        // 创建不可变Set
        Set<String> immutableSet = Set.of("one", "two", "three");
        System.out.println(immutableSet);

        // 创建不可变Map
        Map<String, Integer> immutableMap = Map.of("one", 1, "two", 2);
        System.out.println(immutableMap);
    }
}

运行结果如下:

[one, two, three]
[three, two, one]
{two=2, one=1}

对于List、Set和Map三个接口的of()方法,重载方法的参数有0~10个不等。如果要创建的不可变集合的元素数量超过了10个,就不能再用of()方法了。

对于List和Set的of()方法,重载方法还包含了一个参数args用于接受数量不定的值,这样就可以创建包含任意数量的List、Set。

List的12个重载of()方法:

static <E> List<E> of() {
    return (List<E>) ImmutableCollections.EMPTY_LIST;
}
    
static <E> List<E> of(E e1) {
    return new ImmutableCollections.List12<>(e1);
}

static <E> List<E> of(E e1, E e2) {
    return new ImmutableCollections.List12<>(e1, e2);
}

static <E> List<E> of(E e1, E e2, E e3) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3);
}

static <E> List<E> of(E e1, E e2, E e3, E e4) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
                                                     e6);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
                                                     e6, e7);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
                                                     e6, e7, e8);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
                                                     e6, e7, e8, e9);
}

static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
    return ImmutableCollections.listFromTrustedArray(e1, e2, e3, e4, e5,
                                                     e6, e7, e8, e9, e10);
}

static <E> List<E> of(E... elements) {
    switch (elements.length) { // implicit null check of elements
        case 0:
            @SuppressWarnings("unchecked")
            var list = (List<E>) ImmutableCollections.EMPTY_LIST;
            return list;
        case 1:
            return new ImmutableCollections.List12<>(elements[0]);
        case 2:
            return new ImmutableCollections.List12<>(elements[0], elements[1]);
        default:
            return ImmutableCollections.listFromArray(elements);
    }
}

Set和List一样,同样有12个重载of()方法。

而如果要创建的不可变哈希(HashMap)的数量超过了10个,就不能再用of()方法了,而需要使用ofEntries方法。

Map.ofEntries()的使用如下:

package com.morris.java9;

import java.util.Map;

/**
 * Map.ofEntries(),创建的不可变哈希(HashMap)的数量超过了10个使用
 */
public class MapOfEntriesDemo {
    public static void main(String[] args) {
        Map<Integer, String> map = Map.ofEntries(
                Map.entry(1, "a"),
                Map.entry(2, "b"),
                Map.entry(3, "c"),
                Map.entry(26, "z"));
        System.out.println(map);
    }
}

除了of()方法,Java还提供了copyOf()方法,这个方法可以用来创建一个包含另一个集合所有元素的不可变版本。

List.copyOf()的使用如下:

package com.morris.java9;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * List.copyOf,创建一个包含另一个集合所有元素的不可变版本
 */
public class ListCopyOfDemo {
    public static void main(String[] args) {
        List<String> mutableList = new ArrayList<>(Arrays.asList("one", "two", "three"));
        // 创建不可变List
        List<String> immutableList = List.copyOf(mutableList);
        mutableList.add("four");
        System.out.println(immutableList);
    }
}

运行结果如下:

[one, two, three]

从运行结果可以看出,原集合的修改不影响新集合。

List.copyOf()方法的源码如下:

static <E> List<E> copyOf(Collection<? extends E> coll) {
    return ImmutableCollections.listCopy(coll);
}

static <E> List<E> listCopy(Collection<? extends E> coll) {
  if (coll instanceof List12 || (coll instanceof ListN<?> c && !c.allowNulls)) {
      return (List<E>)coll;
  } else if (coll.isEmpty()) { // implicit nullcheck of coll
      return List.of();
  } else {
      return (List<E>)List.of(coll.toArray());
  }
}

List.copyOf()方法底层使用List.of()来构建不可变集合。

对比两者的区别

安全性

在Java 9之前,虽然使用了Collections.unmodifiableXXX()方法,但是如果原始的可变集合被修改,那么不可变集合的语义就会被破坏,可能会导致UnsupportedOperationException异常。

在Java 9及以后,使用工厂方法创建的集合是真正不可变的,不依赖于任何外部可变集合,因此更加安全。

简洁性

Java 9之前的做法需要首先创建一个可变集合,然后再调用Collections.unmodifiableXXX()来创建不可变版本,代码相对繁琐。

Java 9及以后的做法直接通过工厂方法一步到位,代码更加简洁。

性能

工厂方法创建的不可变集合在内部实现上可能进行了优化,因此可能在某些情况下具有更好的性能。

灵活性

Java 9之前的做法在处理大量元素时可能需要额外的步骤,例如使用Arrays.asList()或循环添加元素到集合中。

Java 9的工厂方法提供了多个重载版本,可以方便地处理不同数量的元素,同时还可以通过copyOf()方法从现有集合创建不可变版本,提供了更多的灵活性。

总的来说,Java 9引入的集合不可变实例工厂方法提高了创建不可变集合的便捷性、安全性和性能,是Java集合API的一个显著改进。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/500463.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day4 linux上部署第一个nest项目(java转ts全栈/3R教室)

背景&#xff1a;上一篇吧nest-vben-admin项目&#xff0c;再开发环境上跑通了&#xff0c;并且build出来了dist文件&#xff0c;接下来再部署到linux试试吧 dist文件夹是干嘛的&#xff1f; 一个pnpn install 直接生成了两个dist文件夹&#xff0c;前端admin项目一个&#xf…

用Kimichat快速识别出图片中的表格保存到Excel

如果有一张图片格式的表格&#xff0c;想要快速复制到Excel表格中&#xff0c;那么一般要借助于OCR工具。之前试过不少在线OCR工具&#xff0c;识别效果差强人意。其实&#xff0c;kimichat就可以非常好的完成这个任务。 下面是一张研报中的表格&#xff0c;只能以图片形式保存…

153 Linux C++ 通讯架构实战8 ,日志打印实战,设置时区,main函数中顺序调整

日志打印实战 //日志的重要性&#xff1a;供日后运行维护人员去查看、定位和解决问题&#xff1b; //新文件&#xff1a;ngx_printf.cxx以及ngx_log.cxx。 //ngx_printf.cxx&#xff1a;放和打印格式相关的函数&#xff1b; //ngx_log.cxx&#xff1a;放和日志相关…

【计算机考研】数学难,到底难在哪里?看这一篇深度分析

数一和数二的难度系数都不在一个重量级&#xff01; 数一这货&#xff0c;容量真不是数二能比的&#xff01;除了高数、线代这些常规操作&#xff0c;还要啃概率论与数理统计这本大厚书&#xff0c;简直是让人头大&#xff01; 考研数学嘛&#xff0c;大家都知道&#xff0c;…

前端是什么

1.前端的概念 1.1 前端的定义 对于网站来说&#xff0c;通常是指网站的前台部分&#xff0c;包括网站的表现层和结构层&#xff08;通俗点就是用户可以看到的部分&#xff09;。总结一下&#xff0c;浏览器、APP、应用程序的界面展现和用户交互就是前端1.2 前端的作用 前端工程…

element跑马灯/轮播图,第一页隐藏左边按钮,最后一页隐藏右边按钮(vue 开箱即用)

图示&#xff1a; 第一步&#xff1a; <el-carousel :class"changeIndex0?leftBtnNone:changeIndeximgDataList.length-1? rightBtnNone:" height"546px" :autoplay"false" change"changeNext"><el-carousel-item v-for…

Android预置应用基础

目录 一、应用预置二、应用预置分区三、编译规则3.1 Android.mk3.2 Android.bp 一、应用预置 预置指智能终端设备出厂前&#xff0c;将文件预先安装到系统中。预置对象包括应用程序、可执行文件、so库&#xff08;.so 文件&#xff09;、jar 包等。 预置方式有以下两种&#…

交换机干道链路

干道链路是用于交换机之间或交换机与路由器之间互连的物理链路。干道链路传输的数据帧都必须打上Tag&#xff0c;便于设备识别数据帧所属的VLAN。因此一条干道链路可以承载多个VLAN的数据帧&#xff0c;如图1-1所示。 图1-1 干道链路功能示意图 干道链路可以透传VLAN。换言之&…

2023年后端面试总结

备注&#xff1a;这篇文章是我在2023年年初在自己的网站上写的&#xff0c;最近在迁移技术文章&#xff0c;我感觉这个也是和咱程序员相关&#xff0c;所以今天就决定把它迁移过来。 .......................................................................分割线..........…

代码随想录算法训练营 Day31 贪心算法1

Day31 贪心算法1 理论基础 贪心算法的本质&#xff1a;找到每个阶段的局部最优&#xff0c;从而去推导全局最优 贪心的两个极端&#xff1a;要么觉得特别简单&#xff0c;要么觉得特别难 贪心无套路 不像二叉树、递归&#xff0c;有固定模式 贪心题目的思考方式 做题的时候…

HarmonyOS实战开发-使用List组件实现导航与内容联动的效果。

1 卡片介绍 使用ArkTS语言&#xff0c;实现一个导航与内容二级联动的效果。 2 标题 二级联动&#xff08;ArkTS&#xff09; 3 介绍 本篇Codelab是主要介绍了如何基于List组件实现一个导航和内容的二级联动效果。样例主要包含以下功能&#xff1a; 切换左侧导航&#xff…

SpringMVC源码分析(七)--数据绑定工厂

1.数据绑定工厂的使用 数据绑定工厂能够创建数据绑定器,将数据绑定到对象中,比如说当接收到请求时,经过http协议解析后数据刚开始都是字符串,此时我们希望将这些属性进行类型转换,并为对象赋值,示例如下: 1)先创建两个实体类Student和Teacher @Getter @Setter @ToSt…

学习鸿蒙基础(10)

目录 一、轮播组件 Swiper 二、列表-List 1、简单的List 2、嵌套的List 三、Tabs容器组件 1、系统自带tabs案例 2、自定义导航栏&#xff1a; 一、轮播组件 Swiper Entry Component struct PageSwiper {State message: string Hello Worldprivate SwCon: SwiperControl…

[Python人工智能] 四十五.命名实体识别 (6)利用keras构建CNN-BiLSTM-ATT-CRF实体识别模型(注意力问题探讨)

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。这篇文章将详细结合如何利用keras和tensorflow构建基于注意力机制的CNN-BiLSTM-ATT-CRF模型,并实现中文实体识别…

基于单片机宿舍防火防盗系统的设计

**单片机设计介绍&#xff0c;基于单片机宿舍防火防盗系统的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机宿舍防火防盗系统的设计概要主要涉及单片机技术的应用&#xff0c;以实现对宿舍环境的防火和防盗功能的…

31-5 命令执行漏洞 - RCE漏洞利用

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、打开pikachu靶场 二、远程命令执行利用 正常情况下这一关卡就是个ping命令,我们只能输入个 ip 靶场就就会ping 这ip 但是我们可以用管道符拼接来执行其他命令,详细可以看我…

Android 开发投屏软件

一、背景 作为Android开发总会有给他人share自己APP情况&#xff0c;一般在线会议投屏&#xff0c;总是需要在手机上安装对应会议软件特别麻烦~ 二、投屏 Android Studio已经自带了投屏能力&#xff0c;可以在电脑端直接控制手机&#xff0c;同步起来非常方便简单 打开步骤 …

【Docker】搭建简单易用的网站分析工具 - umami

【Docker】搭建简单易用的网站分析工具 - umami 前言 本教程基于绿联的NAS设备DX4600 Pro的docker功能进行搭建&#xff0c;采用umami MySQL实例作为演示。 简介 umami是一个开源的、简单的、易于使用的网站分析工具。其设计目的是提供一个简单、易于理解的方式来查看网站…

ATTCK学习笔记

ATT&CK 前言知识 威胁情报&#xff1a;一般为网络流量中或者操作系统上观察到的能高度表明计算机被入侵的痕迹&#xff0c;例如某病毒的Hash值、服务器的IP地址等等。简单来说&#xff0c;威胁情报就像是当计算机被入侵时所表现出来的某种特征&#xff0c;我们将这些威胁…

Kitex 提供的服务注册与发现 etcd 拓展

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 <br> &#x1f4d8;相关专栏<a href"https://blog.csdn.net/studycodeday/category_12460797.html">…