新的本机不可修改集合API

自从Java9开始,JDK里面为集合(List/Set/Map)都添加了of和copyOf方法,他们可以来创建不可变的集合。

Question1:什么叫做不可变集合?

不能对集合进行添加、删除、替换、排序等操作,否则会报java.lang.UnsupportedOperationException错误。

示例代码:

List<String> list = List.of("aa", "bb", "cc");
list.add("dd");

报错信息:

Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:71)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:75)

扩展:Arrays.asList()创建的集合也是一个不可变的集合

Question2:of方法与copyOf方法之间的区别

示例代码:

var list1 = List.of("aa", "bb", "cc");
var copy1 = List.copyOf(list1);
System.out.println(list1 == copy1);
//运行结果: true var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2);
//运行结果: false

注意:var也是Java11新推出的特性局部变量类型推断,这里面不再赘述。

第一段代码和第二段代码差不多,为什么返回结果不一样呢?我们来看一下他们的源码:

    static <E> List<E> of(E e1, E e2, E e3) {
return new ImmutableCollections.ListN<>(e1, e2, e3);
} static final class ListN<E> extends AbstractImmutableList<E>
implements Serializable { static final List<?> EMPTY_LIST = new ListN<>(); @Stable
private final E[] elements; @SafeVarargs
ListN(E... input) {
// copy and check manually to avoid TOCTOU
@SuppressWarnings("unchecked")
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
for (int i = 0; i < input.length; i++) {
tmp[i] = Objects.requireNonNull(input[i]);
}
elements = tmp;
} @Override
public boolean isEmpty() {
return size() == 0;
} @Override
public int size() {
return elements.length;
} @Override
public E get(int index) {
return elements[index];
} private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("not serial proxy");
} private Object writeReplace() {
return new CollSer(CollSer.IMM_LIST, elements);
}
}
    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 AbstractImmutableList && coll.getClass() != SubList.class) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray());
}
}

从源码可以看出,copyOf 方法会先判断来源集合是不是 AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。第二段代码因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false。

扩展:使用Set.of()方法创建Set对象时,不可以包含重复数据

Stream加强

Stream是Java8的新特性,我之前的博客对其进行了详细的介绍:Java8新特性 - Stream API。Java9开始对Stream新增了4个新方法。

增加单个参数构造方法,可为null

在Java8,新建一个值为null的Stream,会报错java.lang.NullPointerException错误。

示例代码:

Stream stream = Stream.of(null);

错误:

Exception in thread "main" java.lang.NullPointerException
at java.util.Arrays.stream(Arrays.java:5004)
at java.util.stream.Stream.of(Stream.java:1000)

错误分析:

查看Stream.of()源码

    @SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
} public static <T> Stream<T> stream(T[] array) {
return stream(array, 0, array.length);
}

可以看见传入null会被解析为时一个数组对象,会进一步访问它的长度信息,导致了NullPointerException异常。

在Java11中,新增了ofNullable方法,可以传入null。因为无法推断类型,所以返回的值为Object,示例代码如下:

Stream stream = Stream.ofNullable(null);
stream.forEach(System.out::println);

从源码中可以看出,当传入的是一个null时,返回的是一个空的对象。

    public static<T> Stream<T> ofNullable(T t) {
return t == null ? Stream.empty()
: StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

增加 takeWhile 和 dropWhile 方法

takeWhile

首先来看一段示例代码:

Stream<Integer> stream = Stream.of(3, 6, 9, 12, 15);
stream.takeWhile(n -> n % 2 != 0)
.forEach(System.out::println);

第一次看这段代码,可能第一印象就是找出流中的奇数打印出来,但是实际输出为:

3

所以takeWhile方法在计算到n % 2 == 0的时候就终止了,takeWhile方法的作用是:从流中一直获取判定器为真的元素,一旦遇到元素为假,就终止处理!

dropWhile

与上面takeWhile一样的代码:

Stream<Integer> stream = Stream.of(3, 6, 9, 12, 15);
stream.dropWhile(n -> n % 2 != 0)
.forEach(System.out::println);

返回的结果为:

6

9

12

15

结果正好与takeWhile相反,dropWhile方法的作用为:只要判定器为真,就一直丢弃元素,直到为假,取为假后的所有元素!

iterate重载

流的迭代,主要用于创建流,在指定初值的情况下,经过处理,然后将处理过的值作为初值,不断迭代。所以iterate创建的是一个无限流。

示例代码:

Stream.iterate(1, t -> 2 * t + 1)
.limit(10)
.forEach(System.out::println);

无限流有一个问题,在数值溢出之后,会一直重复-1的值。Java11进行了优化,以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代,进行有限的迭代,示例代码如下:

Stream.iterate(1, t -> t< 1000, t -> 2 * t + 1)
.forEach(System.out::println);

增加了一系列的字符串处理方法

判断字符串是否为空白

示例代码:

String s1 = " \t \r\n";
System.out.println(s1.isBlank()); // true

去除字符串首尾空白

示例代码:

String s2 = "    \t  123\r\n".strip();
System.out.println(s2); // 123

trim()大部分情况下效果等同于strip(),但是trim()只能去除码值小于等于32的空白字符,不能去除中文情况下的空白字符,strip()可以去除所有语言中的空白

去除尾/首部空格

示例代码:

String s2 = "    \t  123\r\n";
System.out.println(s2.strip().length()); // 3
// 去除首部的空白
System.out.println(s2.stripLeading().length()); // 5
// 去除尾部的空白
System.out.println(s2.stripTrailing().length()); // 10

复制字符串

String s3 = "做一个好人";
System.out.println(s3.repeat(3));
// 做一个好人做一个好人做一个好人

行数统计

String s2 = "    \t  123\r\n123";
System.out.println(s2.lines().count()); //2

s2.lines()获取的是一个流,将字符串根据换行符切割转换为Stream

Optional加强

Optional是Java中引进的容器类,主要用于避免空指针异常,我之前的博客对其进行了详细的介绍:[Java8新特性 - Optional容器类](https://www.cnblogs.com/fx-blog/p/11747058.html"Java8新特性 - Optional容器类")。Java11中Opthonal 也增加了几个非常酷的方法。

ofNullable方法

参照前面Stream增强的介绍,使用Optional.of(T value);传入的参数是null时,会抛出空指针异常,所以Java11中新增了ofNullable,可以兼容空指针,但是实际传入null后要小心,不能用get接收,最好利用orElse方法接收,示例代码如下。

Optional<String> optional = Optional.ofNullable(null);
// 如果内部引用为空,则返回参数中引用,否则返回内部引用
System.out.println(optional.orElse("做一个好人")); // 做一个好人

orElseThrow方法

也可以使用orElseThrow()方法接收,直接在orElseThrow()时抛出异常。

Optional<String> optional = Optional.ofNullable(null);
System.out.println(optional.orElseThrow());

错误如下:

Exception in thread "main" java.util.NoSuchElementException: No value present

at java.base/java.util.Optional.orElseThrow(Optional.java:382)

源码如下:

    public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}

or方法

也可以使用or()方法接收,当一个空 Optional 时给它一个替代的Optional,示例代码如下:

Optional<String> optional = Optional.ofNullable(null);
System.out.println(optional.or(() -> Optional.of("做一个好人!"))
.get()); // 做一个好人!

InputStream加强

Java11中新增了transferTo方法,把输入流中的所有数据直接自动地复制到输出流中,这是在处理原始数据流时非常实用的一种用法,不用写循环,也不需要缓冲区,示例代码如下:

public void test() throws Exception {
var classLoader = this.getClass().getClassLoader();
var inputStream = classLoader.getResourceAsStream("file");
try (var outputStream = new FileOutputStream("file2")) {
inputStream.transferTo(outputStream);
}
inputStream.close();
}

Java11新特性 - 新加一些实用的API的更多相关文章

  1. 重新想象 Windows 8.1 Store Apps (88) - 通信的新特性: 新的 HttpClient

    [源码下载] 重新想象 Windows 8.1 Store Apps (88) - 通信的新特性: 新的 HttpClient 作者:webabcd 介绍重新想象 Windows 8.1 Store ...

  2. Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能

    Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能 1. MySQL  5.6    5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 ...

  3. Atitit.linux 内核 新特性 新功能

    Atitit.linux 内核 新特性 新功能 1.  Linux 3.2内核新特性 2012-02-12 22:41:471 1.1. EXT4:支持更大的块2 1.2. BTRFS:更快的数据清理 ...

  4. Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc

    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc 1.1. Visual Studio2 1.2. ...

  5. Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能

    Atitit.mysql 5.0 5.5  5.6 5.7  新特性 新功能 1. MySQL  5.6    5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 ...

  6. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  7. iOS10 新特性-新功能,以及ReplayKit库

    iOS的10.0 本文总结了iOS的10,运行于目前推出iOS设备推出的主要开发者相关的功能. iOS版10引入了新的方法来增加您的应用程序通过帮助系统参与在适当的时候建议你的应用程序给用户.如果你在 ...

  8. Java 8新特性之旅:使用Stream API处理集合

    在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值. 在之前的文章“遍历.过滤.处理集合及使用Lambda ...

  9. 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!

    写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*) ,那什么是Stream API呢?Java8中的 ...

随机推荐

  1. 编程必备基础知识|计算机组成原理篇(09):CPU的控制器和运算器

    计算机基础方面的知识,对于一些非科班出身的同学来讲,一直是他们心中的痛,而对于科班出身的同学,很多同学在工作之后,也意识到自身所学知识的不足与欠缺,想回头补补基础知识.关于计算机基础的课程很多,内容繁 ...

  2. win10下安装npm&cnpm步骤

    1.node官网下载安装包 2.分别输入node -v,npm -v检查是否完成 3.配置npm的全局模块的存放路径以及cache的路径,新建node_global和node_cache文件,以下是我 ...

  3. Spring boot 官网学习笔记 - Using Spring Boot without the Parent POM,但是还要使用Parent POM提供的便利

    If you do not want to use the spring-boot-starter-parent, you can still keep the benefit of the depe ...

  4. druid 连接池的配置参数

    介绍 DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0.DBCP.PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生 ...

  5. java面向对象,数据类型深入

    java程序员面试题day02 1.类和对象有什么区别? java中的类通过class关键字进行定义,代表的是一种抽象的集合,在类中可以定义各种的属性和方法,代表的是每一个类的实例的特定的数据和动作, ...

  6. Flask基础(03)-->创建第一个Flask程序

    # 导入Flask from flask import Flask # 创建Flask的应用程序 # 参数__name__指的是Flask所对应的模块,其决定静态文件从哪个地方开始寻找 app = F ...

  7. .net core 3.0 Signalr - 07 业务实现-服务端 自定义管理组、用户、连接

    Hub的管理 重写OnConnectedAsync 从连接信息中获取UserId.Groups,ConnectId,并实现这三者的关系,存放于redis中 代码请查看 using CTS.Signal ...

  8. JAVA TCP/IP网络通讯编程(二)

    一个实例通过client端和server端通讯 客户端通过TCP/IP传输资源文件,比如图片,文字,音频,视频等..... 服务端接受到文件存入本地磁盘,返回接受到:“收到来自于"+s.ge ...

  9. vue-cli 脚手架安装

    1.安装node;选择适合自己系统的文件,下载一路next , a安装成功后,打开运行输入cmd 进入命令行: 在命令行工具中输入 npm -v  检查版本号 如果出现 则安装成功:(npm为node ...

  10. Android_布局

    <该文章参考各大博客以及书籍总结而来,如有问题欢迎指出^ ^> 一.五大传统布局+新布局 线性布局——LinearLayout 相对布局——RelativeLayout 帧布局——Fram ...