Set接口

Set是一个不能包含重复元素的Collection,它模拟了数学集抽象,Set接口仅包含从Collection继承的方法,并添加禁止重复元素的限制,Set还为equalshashCode操作的行为添加了一个更强的契约,允许Set实例有意义地进行比较,即使它们的实现类型不同,如果两个Set实例包含相同的元素,则它们是相等的。

Java平台包含三个通用的Set实现:HashSetTreeSetLinkedHashSet。将其元素存储在哈希表中的HashSet是性能最佳的实现,但它不能保证迭代的顺序。TreeSet将其元素存储在红黑树中,根据元素的值对其元素进行排序,它比HashSet慢得多。LinkedHashSet实现为哈希表,其中有一个链表,根据它们插入集合的顺序(插入顺序)对其元素进行排序,LinkedHashSet让它的客户端避免了HashSet提供的未指定的、通常混乱的排序,但代价只稍微高一点。

这是一个简单但有用的Set语法,假设你有一个Collectionc,并且你想要创建另一个包含相同元素的Collection,但会删除所有重复项,下面的一行代码就可以解决这个问题。

Collection<Type> noDups = new HashSet<Type>(c);

它的工作原理是创建一个Set(根据定义,它不能包含重复项),初始化包含c中的所有元素,它使用Collection接口部分中描述的标准转换构造函数。

或者,如果使用JDK 8或更高版本,你可以使用聚合操作轻松收集到Set

c.stream()
.collect(Collectors.toSet()); // no duplicates

这是一个稍长的示例,它将名称Collection累积到TreeSet中:

Set<String> set = people.stream()
.map(Person::getName)
.collect(Collectors.toCollection(TreeSet::new));

以下是第一个语法的次要变体,它在删除重复元素时保留了原始集合的顺序:

Collection<Type> noDups = new LinkedHashSet<Type>(c);

以下是封装前面的语法的泛型方法,返回与传递的相同的泛型类型的Set

public static <E> Set<E> removeDups(Collection<E> c) {return new LinkedHashSet<E>(c);
}

Set接口基础操作

size操作返回Set中的元素数(其基数),isEmpty方法完全符合你的想法,add方法将指定的元素添加到Set(如果它尚不存在)并返回一个布尔值,指示是否添加了元素。类似地,remove方法从Set中删除指定的元素(如果存在)并返回一个布尔值,指示元素是否存在,iterator方法在Set上返回Iterator

以下程序打印出其参数列表中的所有不同单词,提供了该程序的两个版本,第一个使用JDK 8聚合操作,第二个使用for-each构造。

使用JDK 8聚合操作:

import java.util.*;
import java.util.stream.*;public class FindDups {public static void main(String[] args) {Set<String> distinctWords = Arrays.asList(args).stream().collect(Collectors.toSet()); System.out.println(distinctWords.size()+ " distinct words: " + distinctWords);}
}

使用for-each构造:

import java.util.*;public class FindDups {public static void main(String[] args) {Set<String> s = new HashSet<String>();for (String a : args)s.add(a);System.out.println(s.size() + " distinct words: " + s);}
}

现在运行该程序的任一版本。

java FindDups i came i saw i left

生成以下输出:

4 distinct words: [left, came, saw, i]

请注意,代码始终引用Collection通过其接口类型(Set)而不是其实现类型,这是一个强烈推荐的编程实践,因为它使你可以灵活地仅通过更改构造函数来更改实现。如果用于存储集合的变量或用于传递它的参数中的任何一个被声明为Collection的实现类型而不是其接口类型,必须更改所有这些变量和参数才能更改其实现类型。

此外,无法保证生成的程序能够正常运行,如果程序使用原始实现类型中存在但未在新实现类型中存在的任何非标准操作,则程序将失败,仅通过其接口引用集合可防止你使用任何非标准操作。

前面示例中Set的实现类型是HashSet,它不保证Set中元素的顺序,如果你希望程序按字母顺序打印单词列表,只需将Set的实现类型从HashSet更改为TreeSet,进行这个简单的单行更改会导致前一个示例中的命令行生成以下输出。

java FindDups i came i saw i left4 distinct words: [came, i, left, saw]

Set接口批量操作

批量操作特别适合于Set,应用时,它们执行标准的集代数运算,假设s1s2Set,批量操作是这样做的:

  • s1.containsAll(s2) — 如果s2s1的子集,则返回true(如果set s1包含s2中的所有元素,则s2s1的子集)。
  • s1.addAll(s2) — 将s1转换为s1s2的并集(两个集合的并集是包含任一集合中包含的所有元素的集合)。
  • s1.retainAll(s2) — 将s1转换为s1s2的交集(两个集合的交集是仅包含两个集合共有的元素的集合)。
  • s1.removeAll(s2) — 将s1转换为s1s2的(非对称)差集(例如,s1s2的差集就是包含s1中所有元素但不包含s2中的所有元素的集)。

若要非破坏性地计算两个集合的并集、交集或差集(不修改任何一个集合),调用者必须在调用适当的批量操作之前复制一个集合,以下是由此产生的语法。

Set<Type> union = new HashSet<Type>(s1);
union.addAll(s2);Set<Type> intersection = new HashSet<Type>(s1);
intersection.retainAll(s2);Set<Type> difference = new HashSet<Type>(s1);
difference.removeAll(s2);

前面的语法中的结果集的实现类型是HashSet,如前所述,它是Java平台中最好的全能Set实现,但是,任何通用的Set实现都可以替代。

让我们重温一下FindDups程序,假设你想知道参数列表中的哪些单词只出现一次,哪些单词出现多次,但你不希望重复打印出任何重复项,这种效果可以通过生成两个集合来实现 — 一个集合包含参数列表中的每个单词,另一个集合仅包含重复项。仅出现一次的单词是这两组的差集,我们知道如何计算,以下是生成的程序的样子。

import java.util.*;public class FindDups2 {public static void main(String[] args) {Set<String> uniques = new HashSet<String>();Set<String> dups    = new HashSet<String>();for (String a : args)if (!uniques.add(a))dups.add(a);// Destructive set-differenceuniques.removeAll(dups);System.out.println("Unique words:    " + uniques);System.out.println("Duplicate words: " + dups);}
}

当使用前面使用的相同参数列表运行时(i came i saw i left),程序产生以下输出。

Unique words:    [left, saw, came]
Duplicate words: [i]

不太常见的集代数运算是对称差集 — 包含在两个指定集合中但不同时包含在两个集合中的元素的集合,以下代码非破坏性地计算两个集合的对称差集。

Set<Type> symmetricDiff = new HashSet<Type>(s1);
symmetricDiff.addAll(s2);
Set<Type> tmp = new HashSet<Type>(s1);
tmp.retainAll(s2);
symmetricDiff.removeAll(tmp);

Set接口数组操作

除了对其他任何Collection执行的操作之外,数组操作不会对Set执行任何特殊操作,Collection接口部分介绍了这些操作。


上一篇:Collection接口

Java™ 教程(Set接口)相关推荐

  1. java接口有非抽象方法_[Java教程]纳尼,java可以在接口中实现非抽象方法了?

    [Java教程]纳尼,java可以在接口中实现非抽象方法了? 0 2016-09-17 18:00:20 纳尼,接口中可以定义实例方法了?! 纳尼,接口中还可以定义静态方法了?! 没错,在Java8中 ...

  2. java调用easyxml接口_【技术教程】如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口?...

    原标题:[技术教程]如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口? RTSP协议视频平台EasyNVR经过多年的积累,已经是一套成熟且完善的视频平台了,用户可以通过网页直接访 ...

  3. typescript 接口 java_[Java教程]【TypeScript】TypeScript 学习 2——接口

    [Java教程][TypeScript]TypeScript 学习 2--接口 0 2015-06-19 12:00:28 在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScr ...

  4. 微信公众号页面支付接口java,[Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付...

    [Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付 0 2015-09-15 15:00:30 一.调用微信的JS文件 1.首先要绑定[JS接口安全域名],"公众号设置&q ...

  5. java 新浪股票接口api_[Java教程]【API】新浪天气接口 Beta

    [Java教程][API]新浪天气接口 Beta 0 2016-01-25 02:00:04 新浪天氣接口那是公認的好,可是百度之後發現很簡陋,所以自己寫了工具類,此處幫忙測試下其中的天氣接口,看有哪 ...

  6. java中接口什么时候用_我什么时候应该在java中使用接口?

    在Java中精确使用接口的一个很好的例子将是理想的,适用于任何特定的规则. 看看丹以前所有的问题,他似乎只是逐字逐句地张贴家庭作业/考试问题. 令人惊讶的是,这些不是考试题或其他-今天才找到这个网站, ...

  7. java 微信群发多图文_[Java教程]httpClient实现微信公众号消息群发

    [Java教程]httpClient实现微信公众号消息群发 0 2016-09-21 20:00:10 1.实现功能 向关注了微信公众号的微信用户群发消息.(可以是所有的用户,也可以是提供了微信ope ...

  8. java批量删除接口怎么定义_教你在Java接口中定义方法

    基本上所有的Java教程都会告诉我们Java接口的方法都是public.abstract类型的,没有方法体的. 但是在JDK8里面,你是可以突破这个界限的哦. 假设我们现在有一个接口:TimeClie ...

  9. 菜鸟教程中Java语法(Java教程+Java面向对象)

    Java基本数据类型 Java变量类型 Java运算符 Java循环语句 Java条件语句 Java switch case Java Number & Math类 Java Characte ...

  10. java xfire webservice 异步_[Java教程]Java中使用webservice,简化开发(xfire的webservice)...

    [Java教程]Java中使用webservice,简化开发(xfire的webservice) 0 2016-01-07 15:00:11 首先,使用到的jar先导入项目中, xbean-sprin ...

最新文章

  1. 通知 | 2020年度“RONG”奖学金入围答辩名单公布
  2. c语言写简单运行批处理,PC-LINT批处理的简单编写
  3. QT实现minheap(简单图形界面掌握)
  4. lazyload.js详解
  5. obj是什么意思_为什么要学正则表达式 - 3
  6. Redis中的可用性保证之Sentinel 原理
  7. ORACLE PL/SQL编程之八: 把触发器说透
  8. 由底层和逻辑说开去--c++之引用的深入剖析
  9. Mac 配置PHP运行环境
  10. 路由器刷breed web控制台助手_红米AC2100路由器从零认证登录SCUT校园网踩坑经历...
  11. 暑假集训-7.31总结
  12. 商业计划书,有什么idea,模板帮你来
  13. 信捷PLC Modbus通讯 (Modbus_TCP与Modbus_RTU)
  14. 【笔记1-4】陈丹琦毕业论文 NEURAL READING COMPREHENSION AND BEYOND
  15. 怎样将CAD里面画好的图纸转换到WORD文档里面去
  16. turbo linux系统光盘,TurboLinux系统启动软盘的创建方法(转)
  17. 从“我爱你”到“我爱钱”
  18. 2010计算机一级选择题,2010年计算机一级考试选择题题库(最新版)
  19. 修改host文件原理 localhost,127.0.0.1之间有什么区别
  20. 城市公交查询系统的设计与实现

热门文章

  1. Linux驱动设计——字符杂项设备
  2. CPP第四版第五章:位操作符、sizeof及部分编程习题
  3. SQL 触发器 当修改TEST表中的F1字段时,同时根据条件修改F2字段
  4. sql server系统表详细说明(二)(摘)
  5. 细胞冻存及细胞计数的技巧
  6. c、c++、Java和gcc写Hello World
  7. sqlserver没有维护计划_设定数据库备份计划,安全放心不怕事!
  8. Quartus II13.1安装教程
  9. 构造方法与重载:定义一个网络用户类,信息有用户 ID、用户密码、 email 地址。在建立类的实例时把以上三个信息都作为构造函数的参数输入
  10. 数字语音信号处理学习笔记——语音信号的短时时域分析(4)