Java8学习笔记之类库的更新

1、集合

Collection API在Java 8中重大的更新就是引入了流,此外Collection API还有一部分更新。

1)其他新增的方法

Java API的设计者们充分利用默认方法,为集合接口和类新增了多个新的方法。
集合类和接口中新增的方法
  • Map
    Map接口的变化是增加了多个新方法,利用这些新方法能更加便利地操纵Map中的数据。比如,getOrDefault方法就可以替换现在检测Map中是否包含给定键映射的惯用方法。如 果Map中不存在这样的键映射,可以提供一个默认值,方法会返回该默认值。使用之前版本的Java,要实现这一目的,可能会写如下代码:
Map<String, Integer> map = new HashMap<>();
Integer count = 0;
if(map.containsKey("Aston")){
  count = map.get("Aston");
}

使用新Map接口后,只需要编写一行代码就能实现:

Integer count = map.getOrDefault("Aston", 0);

注意:此方法仅在没有映射时才生效。如果键被显式地映射到了空值,那么该方法不会返回设定的默认值。
另一个有用的方法是computeIfAbsent,它能帮助你非常方便地使用缓存模式。比如,我们假设你需要从不同的网站抓取和处理数据。这种场景下,如果能够缓存数据是非常有帮助的,这样就不需要每次都执行数据抓取操作了:

public String getData(String url){
  String data = cache.get(url);
  if(data == null){ //检查数据是否已缓存
    data = getData(url);
    cache.put(url, data); //如果数据没有缓存,就访问网站 抓取数据,紧接着对Map中的数据进行缓存
  }
  return data;
}

现在可以通过computeIfAbsent用更加精炼的方式实现:

public String getData(String url){
  return cache.computeIfAbsent(url, this::getData);
}
  • 集合
    removeIf方法可以移除集合中满足某个谓词的所有元素。它和Stream API中的filter方法不同。Stream API中的filter方法会产生一个新的流,不会对当前作为数据源的流做任何变更。
  • 列表
    replaceAll方法会对列表中的每一个元素执行特定的操作,并用处理的结果替换该元素。它的功能和Stream中的map方法非常相似,不过replaceAll会修改列表中的元素。相反map方法会生成新的元素。
    下面这段代码会打印输出[2,4,6,8,10],因为列表中的元素被原地修改了:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.replaceAll(x -> x * 2);
System.out.println(numbers);
2)Collections类

Collections类的主要功能是操作或返回集合。Java 8中它又 新增了一个方法,该方法可以返回不可修改的、同步的、受检查的或是空的NavigableMap或NavigableSet。此外,它还引入了checkedQueue方法,该方法返回一个队列视图,可以扩展进行动态类型检查。

3)Comparator

Comparator接口现在同时包含了默认方法和静态方法。可以使用静态方法Comparator.comparing返回一个Comparator对象,该对象提供了一个函数可以提取排序关键字。
新的实例方法包含如下方法:

  • reversed:对当前的Comparator对象进行逆序排序,并返回排序后新Comparator对象。
  • thenComparing:两个对象相同时,返回使用另一个Comparator进行比较的Comparator对象。
  • thenComparingInt、thenComparingDouble、thenComparingLong:这些方法的工作方式和thenComparing方法类似,不过它们的处理函数是特别针对某些基本数据类型(分别对应于ToIntFunction、ToDoubleFunction和ToLongFunction)的。

新的静态方法如下:

  • comparingInt、comparingDouble、comparingLong:它们的工作方式和comparing类似,但接受的函数特别针对某些基本数据类型(分别对应于ToIntFunction、 ToDoubleFunction和ToLongFunction)。
  • naturalOrder:对Comparable对象进行自然排序,返回一个Comparator对象。
  • nullsFirst、nullsLast:对空对象和非空对象进行比较,可以指定空对象(null)比非空对象(non-null)小或者比非空对象大,返回值是一个Comparator对象。
  • reverseOrder:和naturalOrder().reversed()方法类似。
2、并发

Java 8中引入了多个与并发相关的更新,如并行流、CompletableFuture类、Arrays类现在支持并发操作。

1)原子操作

java.util.concurrent.atomic包提供了多个对数字类型进行操作的类,比如AtomicInteger和AtomicLong,它们支持对单一变量的原子操作。这些类在Java 8中新增了更多的方法支持。

  • getAndUpdate:以原子方式用给定的方法更新当前值,并返回变更之前的值。
  • updateAndGet:以原子方式用给定的方法更新当前值,并返回变更之后的值。
  • getAndAccumulate:以原子方式用给定的方法对当前及给定的值进行更新,并返回变更之前的值。
  • accumulateAndGet:以原子方式用给定的方法对当前及给定的值进行更新,并返回变更之后的值。
    以原子方式比较一个原子整型值和一个给定的观测值,并将变量设定为二者中较小的一个:
int min = atomicInteger.accumulateAndGet(10, Integer::min);

Adder和Accumulator
在多线程中,如果多个线程需要频繁地进行更新操作,且很少有读取的动作,Java API文档中推荐使用新的类LongAdder、LongAccumulator、DoubleAdder及DoubleAccumulator,尽量避免使用它们对应的原子类型。这些新的类在设计之初就考虑了动态增长的需求,可以有效地减少线程间的竞争。
LongAddr和DoubleAdder类都支持加法操作,而LongAccumulator和DoubleAccumulator可以使用给定的方法整合多个值。
使用LongAdder计算多个值之和:

LongAdder adder = new LongAdder(); //使用默认构造器,初始的sum值为0
adder.add(10); //在多个不同的线程中进行加法运算
// … 
long sum = adder.sum(); //得出sum的值

使用LongAccumulator计算多个值之和:

LongAccumulator acc = new LongAccumulator(Long::sum, 0);
acc.accumulate(10); //在几个不同的线程中累计计算值
// …
long result = acc.get(); //在某个时刻得出结果
2)ConcurrentHashMap

ConcurrentHashMap类极大地提升了HashMap现代化的程度,它对并发的支持非常友好。ConcurrentHashMap允许并发地进行新增和更新操作,因为它仅对内部数据结构的某些部分上锁。和Hashtable比,它具有更高的读写性能。

  • 性能
    为了改善性能,要对ConcurrentHashMap的内部数据结构进行调整。典型情况下,map的条目会被存储在桶中,依据键生成哈希值进行访问。如果大量键返回相同的哈希值,由于桶是由List实现的,它的查询复杂度为O(n),这种情况下性能会恶化。
    在Java 8中,当桶过于臃肿时,它们会被动态地替换为排序树(sorted tree),新的数据结构具有更好的查询性能(排序树的查询复杂度为O(log(n)))。注意,这种优化只有当键是可以比较的(如String或Number类)时才可能发生。
  • 类流操作
    ConcurrentHashMap支持三种新的操作:
    1)forEach:对每个键值对进行特定的操作
    2)reduce:使用给定的精简函数(reduction function),将所有的键值对整合出一个结果
    3)search:对每一个键值对执行一个函数,直到函数的返回值为一个非空值
    以上每种操作都支持四种形式,接受使用键、值、Map.Entry以及键值对的函数:
    1)使用键和值的操作(forEach、reduce、search)
    2)使用键的操作(forEachKey、reduceKeys、searchKeys)
    3)使用值的操作(forEachValue、reduceValues、searchValues)
    4)使用Map.Entry对象的操作(forEachEntry、reduceEntries、searchEntries)

这些操作不会对ConcurrentHashMap的状态上锁。它们只会在运行过程中对元素进行操作。应用到这些操作上的函数不应该对任何的顺序,或其他对象,或在计算过程发生变 化的值,有依赖。
此外,如果需要为这些操作指定一个并发阈值。如果经过预估当前map的大小小于设定的阈值,操作会顺序执行。使用值1开启基于通用线程池的大并行。使用值Long.MAX_VALUE设定程序以单线程执行操作。

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
Optional<Integer> maxValue = Optional.of(map.reduceValues(1, Integer::max));

对int、long和double,它们的reduce操作各有不同(比如reduceValuesToInt、 reduceKeysToLong等)。

  • 计数
    ConcurrentHashMap类提供了一个新方法mappingCount,它以长整型long返回map中映射的数目。应尽量使用这个新方法,而不是老的size方法,size方法返回的类型为int。这是因为映射的数量可能是int无法表示的。
  • 集合视图
    ConcurrentHashMap类还提供了一个名为KeySet的新方法,该方法以Set的形式返回ConcurrentHashMap的一个视图(对map的修改会反映在该Set中,反之亦然)。也可以使用新的静态方法newKeySet,由ConcurrentHashMap创建一个Set。
3、Arrays

Arrays类提供了不同的静态方法对数组进行操作。现在,它又包括了四个新的方法(它们都有特别重载的变量)。

1)使用parallelSort

parallelSort方法会以并发的方式对指定的数组进行排序,可以使用自然顺序,也可以为数组对象定义特别的Comparator。

2)使用setAll和parallelSetAll

setAll和parallelSetAll方法可以以顺序的方式,也可以用并发的方式,使用提供的函数计算每一个元素的值,对指定数组中的所有元素进行设置。该函数接受元素的索引,返回该索引元素对应的值。由于parallelSetAll需要并发执行,所以提供的函数必须没有任何副作用。
使用setAll方法生成一个值为0, 2, 4, 6, …的数组:

int[] numbers = new int[10];
Arrays.setAll(numbers , i -> i * 2);
3)使用parallelPrefix

parallelPrefix方法以并发的方式,用用户提供的二进制操作符对给定数组中的每个元素进行累积计算。
使用parallelPrefix并发地累积数组中的元素:

int[] ones = new int[10];
Arrays.fill(ones, 1);
Arrays.parallelPrefix(ones, (a, b) -> a + b); //ones现在的内容是[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
4、Number和Math

Java 8 API对Number和Math也做了改进,为它们增加了新的方法。

1)Number

Number类中新增的方法如下:

  • Short、Integer、Long、Float和Double类提供了静态方法sum、min和max。
  • Integer和Long类提供了compareUnsigned、divideUnsigned、remainderUnsigned和toUnsignedLong方法来处理无符号数。
  • Integer和Long类也分别提供了静态方法parseUnsignedInt和parseUnsignedLong将字符解析为无符号int或long类型。
  • Byte和Short类提供了toUnsignedInt和toUnsignedLong方法通过无符号转换将参数转化为int或long类型。类似地,Integer类也提供了静态方法toUnsignedLong。
  • Double和Float类提供了静态方法isFinite,可以检查参数是否为有限浮点数。
  • Boolean类现在提供了静态方法logicalAnd、logicalOr和logicalXor,可以在两个boolean之间执行and、or和xor操作。
  • BigInteger类提供了byteValueExact、shortValueExact、intValueExact和longValueExact,可以将BigInteger类型的值转换为对应的基础类型。如果在转换过程中有信息丢失,方法会抛出算术异常。
2)Math

如果Math中的方法在操作中出现溢出,Math类提供了新的方法可以抛出算术异常。支持这一异常的方法包括使用int和long参数的addExact、subtractExact、multipleExact、incrementExact、decrementExact和negateExact。
此外,Math类还新增了一个静态方法toIntExact,可以将long值转换为int值。其他的新增内容包括静态方法floorMod、floorDiv 和nextDown。

5、Files

Files类引人注目的改变是,可以用文件直接产生流。通过新的静态方法Files.lines,可以以延迟方式读取文件的内容,并将其作为一个流。此外,还有一些非常有用的静态方法可以返回流:

  • Files.list:生成由指定目录中所有条目构成的Stream<Path>。这个列表不是递归包含的。由于流是延迟消费的,处理包含内容非常庞大的目录时,这个方法非常有用。
  • Files.walk:和Files.list类似,它也生成包含给定目录中所有条目的Stream<Path>。不过这个列表是递归的,可以设定递归的深度。注意,该遍历是依照深度优先进行的。
  • Files.find:通过递归遍历一个目录找到符合条件的条目,并生成一个Stream<Path>对象。
6、Reflection

Reflection API的变化就是为了支撑注解机制的改变。此外,Relection接口的另一个变化是新增了可以查询方法参数信息的API。比如,可以使用新增的java.lang.reflect.Parameter类查询方法参数的名称和修饰符,这个类被新的java.lang.reflect.Executable类所引用,而java.lang.reflect.Executable通用函数和构造函数共享的父类。

7、String

String类也新增了一个静态方法join。它可以用一个分隔符将多个字符串连接起来。

String authors = String.join(", ", "a", "b", "c");
System.out.println(authors); //a,b,c

--参考文献《Java8实战》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容

  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,268评论 0 16
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 2,388评论 0 4
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,504评论 0 3
  • java基础 集合承继包含图 Collection vs Collections 首先,"Collection" ...
    onlyHalfSoul阅读 1,327评论 0 5
  • 2018年9月2日 邹红旭~常州新日催化剂有限公司 【日精进打卡第36天】 【知~学习】 《六项精进》0遍 共88...
    Zou_84fd阅读 172评论 0 0