新的本机不可修改集合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. webstorm中关闭烦人Eslint语法检查

    打开许久没打开的webstrom,以前关闭的配置不知道怎么又乱了,react项目到处报错,真是没法忍. 关闭eslint位置:File-->Setting-->Languages& ...

  2. 如何在服务器中安装mysql 以及安装禅道

    安装mysql:以下命令在xshell 中输入: 1.卸载mysql :yum -y remove mysql* 2.查找mysql命名安装的所有文件: find / -name mysql  只能删 ...

  3. Java面向对象笔记(五分钟秒懂)

    面向对象概念 面向对象三大特征:封装,继承,多态 面向对象编程(OOP,Object Oriented Programing)是相对于面向过程编程说的,之前写的代码基本都是纯的面向过程编程的,当项目复 ...

  4. GStreamer基础教程09 - Appsrc及Appsink

    摘要 在我们前面的文章中,我们的Pipline都是使用GStreamer自带的插件去产生/消费数据.在实际的情况中,我们的数据源可能没有相应的gstreamer插件,但我们又需要将数据发送到GStre ...

  5. LINUX系统学习以及初学者系统下载

    Linux系统常用命令大全 来源:服务器之家 [博客中所有文章如有不对的地方希望看官们指出,有问题也可以提出来相互交流,相互学习,感谢大家!] 初学者建议安装:sentOS Ubuntu系统下载连接h ...

  6. Jquery Ztree异步加载树

    1. 下载jquery的JS文件/ztree的CSS文件和JS文件 https://jquery.com/download/ https://gitee.com/zTree/zTree_v3/tree ...

  7. 使用XAMPP配置Apache服务器反向代理

    反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时 ...

  8. Java 学习笔记之 Daemon线程

    Daemon线程: 线程: 用户线程 守护线程 守护线程是一种特殊的线程,在进程中不存在非守护线程了,则守护线程自动销毁. public class DaemonThread extends Thre ...

  9. Scala 学习笔记之集合(4)

    集合的模式匹配操作: object CollectionDemo5 { def main(args: Array[String]): Unit = { //集合模式匹配1 val ls = List( ...

  10. 面试|简单描述MySQL中,索引,主键,唯一索引,联合索引 的区别,对数据库的性能有什么影响(从读写两方面)

    索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们 包含着对数据表里所有记录的引用指针. 普通索引(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的 ...