《Java8实战》第8章 Collection API 的增强功能

这篇具有很好参考价值的文章主要介绍了《Java8实战》第8章 Collection API 的增强功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

8.1 集合工厂

如果我想创建一个集合,之前的做法是先new一个list,然后再一个个的add,这样子有点繁琐。
现在的方法可以这样,是使用 Arrays.asList()工厂方法:
List<String> friends = Arrays.asList("Raphael", "Olivia", "Thibaut");
但是这样子创建只能更新,不可以增加、删除。

8.1.1 List 工厂

工厂方法 List.of方法,创建的是一个只读的列表。
它可以保护你的集合,以免被意外地修改。
建议是除非你需要进行某种形式的数据处理并对数据进行转换,否则应该尽量使用工厂方法。工厂方法使用起来更简单,实现也更容易,并且在大多数情况下就够用了。

8.1.2 Set 工厂

创建一个set集合 Set.of
Set<String> friends = Set.of("Raphael", "Olivia", "Thibaut");

8.1.3 Map 工厂

与list、set相比,创建map稍显复杂,因为你需要同时传递键和值。Java 9中提供了两种初始化一个不可变 Map 的方式。
Map<String, Integer> ageOfFriends = Map.of("Raphael", 30, "Olivia", 25, "Thibaut", 26);
如果你只需要创建不到 10 个键值对的小型 Map,那么使用这种方法比较方便。
规模比较大的话,就使用Map.ofEntries 的工厂方法,该工厂方法接受以变长参数列表形式组织的 Map.Entry<K, V>对象作为参数

import static java.util.Map.entry; 
Map<String, Integer> ageOfFriends 
       = Map.ofEntries(entry("Raphael", 30), 
       entry("Olivia", 25), 
       entry("Thibaut", 26)); 
System.out.println(ageOfFriends); 

8.2 使用 List 和 Set

Java 8 在 List 和 Set 的接口中新引入了以下方法。

  • removeIf 移除集合中匹配指定谓词的元素。实现了 List 和 Set 的所有类都提供了该方法(事实上,这个方法继承自 Collection 接口)。
  • replaceAll 用于 List 接口中,它使用一个函数(UnaryOperator)替换元素。
  • sort 也用于 List 接口中,对列表自身的元素进行排序。
8.2.1 removeIf 方法

循环的时候remove就会抛异常,ConcurrentModificationException。因为在底层实现上,for-each 循环使用了一个迭代器对象,集合由两个不同的对象管理着
一般解决这个问题就需要显示的调用Iterator 对象,并通过它调用 remove()方法

for (Iterator<Transaction> iterator = transactions.iterator(); 
 iterator.hasNext(); ) { 
 Transaction transaction = iterator.next(); 
 if(Character.isDigit(transaction.getReferenceCode().charAt(0))) { 
    iterator.remove(); 
  } 
} 

不过这样子的话,代码就显得繁琐,所以就可以使用removeIf了,
transactions.**removeIf**(transaction -> Character.isDigit(transaction.getReferenceCode().charAt(0)));

8.2.2 replaceAll 方法

List 接口提供的 replaceAll 方法让你可以使用一个新的元素替换列表中满足要求的每个元素。
原来的方式:

referenceCodes.stream() 
 .map(code -> Character.toUpperCase(code.charAt(0)) + 
 code.substring(1)) 
 .collect(Collectors.toList()) 
 .forEach(System.out::println);
输入: [a12, C14, b13] 
输出: A12, C14, B13

或者
for (ListIterator<String> iterator = referenceCodes.listIterator(); iterator.hasNext(); ) { 
 String code = iterator.next(); 
 iterator.set(Character.toUpperCase(code.charAt(0)) + code.substring(1)); 
} 

现在可以这样子:
referenceCodes.replaceAll(code -> Character.toUpperCase(code.charAt(0)) + code.substring(1));

8.3 使用 Map

Java 8 在 Map 接口中新引入了几个默认方法

8.3.1 forEach 方法

使用 Map.Entry<K, V>迭代器访问 Map 集合中的每一个元素:

for(Map.Entry<String, Integer> entry: ageOfFriends.entrySet()) { 
 String friend = entry.getKey(); 
 Integer age = entry.getValue(); 
 System.out.println(friend + " is " + age + " years old"); 
} 

从 Java 8 开始,Map 接口开始支持 forEach 方法,该方法接受一个 BiConsumer,以 Map的键和值作为参数。
ageOfFriends.forEach((friend, age) -> System.out.println(friend + " is " + age + " years old"));

8.3.2 排序

Entry.comparingByValue 、Entry.comparingByKey这两个可以帮助map排序

favouriteMovies 
 .entrySet() 
 .stream() 
 .sorted(Entry.comparingByKey()) 
 .forEachOrdered(System.out::println);
8.3.3 getOrDefault 方法

当获取的对象不存在的话,就返回一个默认值
System.out.println(favouriteMovies.getOrDefault("Olivia", "Matrix"));
如果key为Olivia的值不存在,那么就返回"Matrix"

8.3.4 计算模式

就是如果key不存在,那么就执行某个操作

  • computeIfAbsent——如果指定的键没有对应的值(没有该键或者该键对应的值是空),那么使用该键计算新的值,并将其添加到 Map 中;
  • computeIfPresent——如果指定的键在 Map 中存在,就计算该键的新值,并将其添加到 Map 中;
  • compute——使用指定的键计算新的值,并将其存储到 Map 中。

computeIfAbsent 的一个应用场景是缓存信息。
// 如果key不存在就执行calculateDigest操作
lines.forEach(line -> dataToHash.computeIfAbsent(line, this::calculateDigest));
还有这个场景,

String friend = "Raphael"; 
List<String> movies = friendsToMovies.get(friend); 
if(movies == null) { 
 movies = new ArrayList<>(); 
 friendsToMovies.put(friend, movies); 
} 
movies.add("Star Wars"); 

优化
friendsToMovies.computeIfAbsent("Raphael", name -> new ArrayList<>()) 
 .add("Star Wars");
8.3.5 删除模式

java提供了一个重载方法的remove方法。
可能是这样子删除的:判断map的key存在,再比较值是否相等,然后再删除

String key = "Raphael"; 
String value = "Jack Reacher 2"; 
if (favouriteMovies.containsKey(key) && 
 Objects.equals(favouriteMovies.get(key), value)) { 
   favouriteMovies.remove(key); 
   return true; 
} else { 
 return false; 
}

现在这样:
favouriteMovies.remove(key, value);
vlaue小于10就删除
movies.entrySet().removeIf(entry -> entry.getValue() < 10);

8.3.6 替换模式

Map 中提供了两种新的方法来替换其内部映射项,分别是:

  • replaceAll——通过 BiFunction 替换 Map 中每个项的值。该方法的工作模式类似于之前介绍过的 List 的 replaceAll 方法;
  • Replace——如果键存在,就可以通过该方法替换 Map 中该键对应的值。它是对原有replace 方法的重载,可以仅在原有键对应某个特定的值时才进行替换。

movie 就是value
favouriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());

8.3.7 merge 方法
Map<String, String> friends = Map.ofEntries(entry("Raphael", "Star Wars")); 
Map<String, String> everyone = new HashMap<>(family); 
everyone.putAll(friends); 
System.out.println(everyone); 

但是如果是有冲突的合并需要处理,可以这样

Map<String, String> family = Map.ofEntries( 
 entry("Teo", "Star Wars"), entry("Cristina", "James Bond")); 
Map<String, String> friends = Map.ofEntries( 
 entry("Raphael", "Star Wars"), entry("Cristina", "Matrix")); 

Map<String, String> everyone = new HashMap<>(family); 
friends.forEach((k, v) -> 
 everyone.merge(k, v, (movie1, movie2) -> movie1 + " & " + movie2)); // 如果存在重复的键,就连接两个值
System.out.println(everyone); 

merge 方法处理空值的方法相当复杂,在 Javadoc 文档中是这么描述的:
如果指定的键并没有关联值,或者关联的是一个空值,那么[merge]会将它关联到指定的非空值。否则,[merge]会用给定映射函数的[返回值]替换该值,如果映射函数的返回值为空就删除[该键]。

8.4 改进的 ConcurrentHashMap

并发安全,使用的是分段锁

8.4.1 归约和搜索

ConcurrentHashMap 类支持三种新的操作

  • forEach——对每个(键, 值)对执行指定的操作;
  • reduce——依据归约函数整合所有(键, 值)对的计算结果;
  • search——对每个(键, 值)对执行一个函数,直到函数取得一个非空值。

每种操作支持四种形式的参数,接受函数使用键、值、Map.Entry 以及(键, 值)对作为参数:

  • 使用键(forEachKey,reduceKeys,searchKeys);
  • 使用值(forEachValue,reduceValues,searchValues);
  • 使用 Map.Entry 对象(forEachEntry,reduceEntries,searchEntries);
  • 使用键和值(forEach,reduce,search)。
ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>(); 
long parallelismThreshold = 1; 
Optional<Integer> maxValue = 
 Optional.ofNullable(map.reduceValues(parallelismThreshold, Long::max)); 
8.4.2 计数

ConcurrentHashMap 类提供了一个新的 mappingCount 方法,能以长整形 long 返回 Map中的映射数目。你应该尽量在新的代码中使用它,而不是继续使用返回 int 的 size 方法。

8.4.3 Set 视图

ConcurrentHashMap 类还提供了一个新的 keySet 方法,该方法以 Set 的形式返回ConcurrentHashMap 的一个视图(Map 中的变化会反映在返回的 Set 中,反之亦然)。
文章来源地址https://www.toymoban.com/news/detail-423207.html

8.5 小结

  • Java 9 支持集合工厂,使用 List.of、Set.of、Map.of 以及 Map.ofEntries 可以创建小型不可变的 List、Set 和 Map。
  • 集合工厂返回的对象都是不可变的,这意味着创建之后你不能修改它们的状态。
  • List 接口支持默认方法 removeIf、replaceAll 和 sort。
  • Set 接口支持默认方法 removeIf。
  • Map 接口为常见模式提供了几种新的默认方法,并降低了出现缺陷的概率。
  • ConcurrentHashMap 支持从 Map 中继承的新默认方法,并提供了线程安全的实现。

到了这里,关于《Java8实战》第8章 Collection API 的增强功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java笔记(15) Collection集合-->List集合

    集合的理解和好处 数组一旦定义,长度即固定,不能修改。要添加新元素需要新建数组,然后循环拷贝,非常麻烦 集合可以动态保存任意多个对象,使用比较方便 提供饿了一系列方便的操作对象的方法:add、remove、set、get等 使用集合添加、删除新元素的示意代码,简洁明了

    2023年04月14日
    浏览(48)
  • Java笔记(16) Collection集合-->Set集合-->HashSet

    Set是无序集合(添加和取出的顺序不一致,但取出的顺序是固定的),没有索引 不允许重复元素,所以最多包含一个null JDK API中Set接口的实现类有: Abstract, ConcurrentHashMap.KeySetView, ConcurrentSkipListSet, CopyOnWriteArraySet, EnumSet, HashSet, JobStateReasons, LinkedHashSet, TreeSet Set接口和List接口一

    2023年04月15日
    浏览(60)
  • 【从零开始学Java66】讲解Java集合中的Collection体系

    本文将为大家详细讲解Java中的Collection体系,这是我们进行开发时经常用到的知识点,也是大家在学习Java中很重要的一个知识点,更是我们在面试时有可能会问到的问题。 文章较长,干货满满,建议大家收藏慢慢学习。文末有本文重点总结,主页有全系列文章分享。技术类问

    2024年02月06日
    浏览(43)
  • 49天精通Java,第23天,Java集合,Collection接口,Iterator接口

    大家好,我是哪吒。 在Java类库中,集合类的基类是Collection接口。

    2023年04月11日
    浏览(43)
  • Java基础六 - Collection集合List、Set、Queue,Map

    1. List - ArrayList、LinkedList、Vector ArrayList         2. LinkedList         3. Vector         4. 常见使用方法 2. Set - HashSet、LinkedHashSet、TreeSet 1. HashSet 2. LinkedHashSet 3. TreeSet 4. 常用方法 3. Map - HashMap、TreeMap、LinkedHashMap、Hashtable 1. HashMap 2. LinkedHashMap 3. TreeMap 4. Hashtable 5.

    2024年02月14日
    浏览(49)
  • 从零开始学习 Java:简单易懂的入门指南之Collection集合及list集合(二十一)

    1.1数组和集合的区别 相同点 都是容器,可以存储多个数据 不同点 数组的长度是不可变的,集合的长度是可变的 数组可以存基本数据类型和引用数据类型 集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类 1.2集合类体系结构 1.3Collection 集合概述和使用 Collec

    2024年02月10日
    浏览(41)
  • Java8 - 将 List 集合转为 Map

    1. 将List转为Map:key=userId, value=name 输出: 2. 将List转为Map:key=userId, value=User对象 输出: 3. 重复的 key 处理 如果出现相同的key,那么会抛出重复key的异常,比如我们将userId为3的修改为2,则会和第二个用户冲突: 抛出异常: Collectors.toMap支持第三个参数,对重复值进行选取:

    2024年02月08日
    浏览(103)
  • 【JAVA学习笔记】 56 - 开发中如何选择集合实现类,以及Collection工具类

    https://github.com/yinhai1114/Java_Learning_Code/blob/main/IDEA_Chapter14/src/com/yinhai/Collections_.java 目录 项目代码 Collections工具类 一、Collections工具类介绍 1.排序操作: (均为static方法) 2.查找、替换 在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行 选择

    2024年02月06日
    浏览(42)
  • 【JAVA学习笔记】53 - 集合-List类及其子类Collection、ArrayList、LinkedList类

    https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/collection_ https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/list_ 目录 项目代码 集合 一、引入 数组 集合 二、集合的框架体系 单列集合        双列集合        Collection类 一、Collection类接

    2024年02月06日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包