1、集合框架概述

(1)集合框架作用

在实际开发中,我们经常会对一组相同类型的数据进行统一管理操作。到目前为止,我们可以使用数组结构、链表结构、二叉树结构来实现。

数组的最大问题在于数组中的元素个数是固定的,要实现动态数组,必竟还是比较麻烦, 自己实现链表或二叉树结构来管理对象更是不方便。

在JDK1.2版本后,JAVA完整的提供了类集合的概念,封装了一组强大的、非常方便的集合 框架API,让我们在开发中大大的提高了效率。 集合中分为三大接口:

Collection、Map、Iterator

集合框架的接口和类在java.util包中

(2)Collection接口

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。

一些 collection 允许有重复的元素,而另一些则不允许。

一些 collection 是有序的,而另一些则是无序的。

JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些collection。 接口的定义:

  1. public interface Collection<E>
  2. extends Iterable<E>

2、集合框架List接口

(1)List接口

  1. public interface List extends Collection<E>

有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

(2)ArrayList

  1. public class ArrayList<E> extends AbstractList<E>
  2. implements List<E>, RandomAccess, Cloneable, Serializable

List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有 元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。

  • 使用add来添加元素,可以指定位置
  • 使用size来获取长度大小
  • 使用get来获取相应的数值
  • 使用remove来删除某个元素
  • 使用contains来查看是否包含某个元素
  • 使用set来用指定元素替换列表中指定位置的元素
  • 使用toArray将集合转换成数组

(3)Vector

  1. public class Vector<E> extends AbstractList<E>
  2. implements List<E>, RandomAccess, Cloneable, Serializable

Vector 类可以实现可增长的对象数组。 与数组一样, 它包含可以使用整数索引进行访问的组件。 但是, Vector 的大小可以根据需要增大或缩小, 以适应创建 Vector 后进行添加或移除项的操作

与ArrayList最大的区别是线程是安全的,适合多线程访问时使用,但在单线程效率较低

(4)LinkedList

  1. public class LinkedList<E> extends AbstractSequentialList<E>
  2. implements List<E>, Deque<E>, Cloneable, Serializable

List 接口的链接列表实现。 实现所有可选的列表操作, 并且允许所有元素(包括 null)。除了实现 List 接口外, LinkedList 类还为在列表的开头及结尾 get、 remove 和 insert 元素提供了统一的命名方法。


ListDemo

  1. import java.util.ArrayList;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Vector;
  5. /**
  6. * Collection接口:用于存储单个对象的集合
  7. * List接口:
  8. * 1、有序的,可以重复
  9. * 2、允许多个 null 元素
  10. * 3、具体的实现有常用的:ArrayList,Vector,LinkedList
  11. * 在实际开发中,我们如何选择list的具体实现?
  12. * 1、安全性问题 Vector
  13. * 2、是否频繁插入,删除操作 LinkedList
  14. * 3、是否是存储后遍历 ArrayList
  15. *
  16. * Set接口:
  17. * @description
  18. */
  19. public class ListDemo {
  20. /**
  21. * LinkedList
  22. * 1、实现原理,采用双向链表结构实现
  23. * 2、适合插入,删除操作,性能高
  24. *
  25. */
  26. private static void linkedList(){
  27. LinkedList<String> list = new LinkedList<>();
  28. list.add("王老师");
  29. list.add("李老师");
  30. list.add("张老师");
  31. list.add("毕老师");
  32. for(int i=0;i<list.size();i++){
  33. System.out.println(list.get(i));
  34. }
  35. }
  36. /**
  37. * Vector
  38. * 1、实现原理,采用动态对象数组实现,默认构造方法创建了一个大小为10的对象数组
  39. * 2、扩充的算法:当增量为0时,扩充为原来大小的2倍,当增量大于0时,扩充为原来大小+增量
  40. * 3、不适合删除或插入操作
  41. * 4、为了防止数组动态扩充次数过多,建议创建Vector时,给定初始容量
  42. * 5、线程安全,适合在多线程访问时使用,在单线程下使用效率较低
  43. * 面试题 :Vector与ArrayList的区别?
  44. */
  45. private static void vector(){
  46. Vector<String> v = new Vector<>();
  47. v.add("王老师");
  48. v.add("李老师");
  49. v.add("张老师");
  50. v.add("毕老师");
  51. for(int i=0;i<v.size();i++){
  52. System.out.println(v.get(i));
  53. }
  54. }
  55. /**
  56. * ArrayList(1.8)
  57. * 1、实现原理,采用动态对象数组实现,默认构造方法创建了一个空数组
  58. * 2、第一次添加元素,扩展容量为10,之后的扩充算法:原来数组大小+原来数组的一半
  59. * 3、不适合进行删除或插入操作
  60. * 4、为了防止数组动态扩充次数过多,建议创建ArrayList时,给定初始容量
  61. * 5、多线程中使用不安全,适合在单线程访问时使用,效率较高
  62. * JDK1.2开始
  63. */
  64. private static void arrayList(){
  65. //使用集合来存储多个不同类型的元素(对象),那么在处理时会比较麻烦,实际开发中,不建议
  66. //这样使用,我们应该在一个集合中存储相同的类型对象
  67. List<String> list = new ArrayList<>();
  68. list.add("王老师");
  69. list.add("李老师");
  70. list.add(1,"张老师");
  71. list.add("毕老师");
  72. // list.add(10);
  73. //遍历集合
  74. int size = list.size();
  75. for(int i=0;i<size;i++){
  76. System.out.println(list.get(i));
  77. }
  78. System.out.println(list.contains("王老师"));
  79. list.remove("毕老师");
  80. System.out.println(list.size());
  81. list.set(0,"赵老师");
  82. int index = list.indexOf("李老师");
  83. System.out.println(index);
  84. String[] strings = list.toArray(new String[list.size()]);
  85. for(String str:strings){
  86. System.out.println(str);
  87. }
  88. System.out.println("--------------");
  89. String[] array = list.toArray(new String[]{});
  90. for(String s: array){
  91. System.out.println(s);
  92. }
  93. System.out.println("---------------");
  94. for(String str:list){
  95. System.out.println(str);
  96. }
  97. }
  98. public static void main(String[] args) {
  99. // arrayList();
  100. vector();
  101. // linkedList();
  102. }
  103. }

3、 集合框架Set接口

(1)Set接口

  1. public interface Set<E> extends Collection<E>

一个不包含重复元素的 collection。 更确切地讲, set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2, 并且最多包含一个 null 元素。 正如其名称所暗示的, 此接口模仿了数学上的 set 抽象。

(2)HashSet

  1. public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable

类实现 Set 接口, 由哈希表(实际上是一个 HashMap 实例) 支持。 它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。 此类允许使用 null 元素

hashCode深入分析:

hashcode() 方法, 在object类中定义如下:

  1. public native int hashCode();

hashCode是本地方法, 它的实现是根据本地机器相关, 当然我们可以在自己写的类中覆盖hashcode()方法, 比如String、 Integer、 Double… 等等这些类都是覆盖了hashcode()方法的。

在java的集合中, 判断两个对象是否相等的规则是:可通过重写hashCode以及equals

  1. 判断两个对象的hashCode是否相等如果不相等, 认为两个对象也不相等, 结束如果相等, 转入2
  2. 判断两个对象用equals运算是否相等如果不相等, 认为两个对象也不相等如果相等, 认为两个对象相等
    (equals()是判断两个对象是否相等的关键)

没有get方法

(3)TreeSet

  1. public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable

基于 TreeMap 的 NavigableSet 实现。 使用元素的自然顺序对元素进行排序, 或者根据创建 set 时提供的 Comparator 进行排序, 具体取决于使用的构造方法。

(4)LinkedHashSet

  1. public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable, Serializable

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。 此实现与 HashSet 的不同之外在于, 后者维护着一个运行于所有条目的双重链接列表。 此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序) 进行迭代。 注意, 插入顺序不受在 set 中重新插入的 元素的影响。 (如果在 s.contains(e) 返回 true 后立即调用 s.add(e), 则元素 e 会被重新插入到 set s 中。 )


SetDemo

  1. import java.util.HashSet;
  2. import java.util.LinkedHashSet;
  3. import java.util.Set;
  4. import java.util.TreeSet;
  5. /**
  6. * Set接口
  7. * 1、无序的(不保证顺序)
  8. * 2、不允许重复元素
  9. * HashSet、TreeSet、LinkedHashSet
  10. *
  11. * 如果要排序,选择treeSet
  12. * 如果不要排序,也不用保正顺序选择HashSet
  13. * 不要排序,要保正顺序,选择LinkedHashSet
  14. * @description
  15. */
  16. public class SetDemo {
  17. /**
  18. * 哈希表和链接列表实现,
  19. * 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。
  20. */
  21. private static void linkedHashSet(){
  22. LinkedHashSet<Cat> set = new LinkedHashSet<>();
  23. Cat c1 = new Cat("miaomiao",5,1);
  24. Cat c2 = new Cat("huahua",2,2);
  25. Cat c3 = new Cat("tom",5,3);
  26. Cat c4 = new Cat("miaomiao",3,1);
  27. set.add(c1);
  28. set.add(c2);
  29. set.add(c3);
  30. set.add(c4);
  31. for(Cat c: set){
  32. System.out.println(c);
  33. }
  34. }
  35. /**
  36. * 有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现,
  37. * 对象比较器还可以用来去除重复元素,如果自定义的数据类,没有实现比较器接口,将无法添加到TreeSet集合中。
  38. */
  39. private static void treeSet(){
  40. TreeSet<Cat> tree = new TreeSet<>(new CatComparator());
  41. Cat c1 = new Cat("miaomiao",5,1);
  42. Cat c2 = new Cat("huahua",2,2);
  43. Cat c3 = new Cat("tom",5,3);
  44. Cat c4 = new Cat("miaomiao",3,1);
  45. tree.add(c1);
  46. tree.add(c2);
  47. tree.add(c3);
  48. tree.add(c4);
  49. System.out.println(tree.size());
  50. for(Cat c: tree){
  51. System.out.println(c);
  52. }
  53. }
  54. /**
  55. * HashSet
  56. * 1、实现原理,基于哈希表(HashMap)实现
  57. * 2、不允许重复,可以有一个NULL元素
  58. * 3、不保证顺序恒久不变
  59. * 4、添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象
  60. * 5、排除重复元素是通过equals来检查对象是否相同
  61. * 6、判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是
  62. * 同一个对象),如果不同,则两个对象不是同一个对象,如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对比象。
  63. * 7、自定义对象要认为属性值都相同时为同一个对象,有这种需求时,那么我们要重写对象所在类的hashCode和equals方法。
  64. *
  65. * 小结
  66. * (1)哈希表的存储结构:数组+链表,数组里的每个元素以链表的形式存储
  67. * (2)如何把对象存储到哈希表中,先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的哪个位置
  68. * (3)解决hashSet中的重复值使用的方式是,参考第6点
  69. */
  70. private static void hashSet(){
  71. Set<String> set = new HashSet<>();
  72. set.add("飞飞");
  73. set.add("备备");
  74. set.add("亮亮");
  75. set.add("关关");
  76. set.add("曹操");
  77. set.add("亮亮");
  78. System.out.println(set.size());
  79. String[] names = set.toArray(new String[]{});
  80. for(String s: names){
  81. System.out.println(s);
  82. }
  83. Cat c1 = new Cat("miaomiao",5,1);
  84. Cat c2 = new Cat("huahua",2,2);
  85. Cat c3 = new Cat("tom",5,3);
  86. Cat c4 = new Cat("miaomiao",5,1); //c4与c1使用equals不同
  87. Set<Cat> cats = new HashSet<>();
  88. cats.add(c1);
  89. cats.add(c2);
  90. cats.add(c3);
  91. cats.add(c4);
  92. //cats.add(c1);
  93. System.out.println(cats.size());
  94. for(Cat c: cats){
  95. System.out.println(c);
  96. }
  97. System.out.println("c1="+c1.hashCode());
  98. System.out.println("c2="+c2.hashCode());
  99. System.out.println("c3="+c3.hashCode());
  100. System.out.println("c4="+c4.hashCode());
  101. }
  102. public static void main(String[] args) {
  103. // hashSet();
  104. // treeSet();
  105. linkedHashSet();
  106. }
  107. }

Cat

  1. public class Cat {
  2. private String name;
  3. private int age;
  4. private int id;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public int getAge() {
  12. return age;
  13. }
  14. public void setAge(int age) {
  15. this.age = age;
  16. }
  17. public int getId() {
  18. return id;
  19. }
  20. public void setId(int id) {
  21. this.id = id;
  22. }
  23. @Override
  24. public String toString() {
  25. return "Cat [name=" + name + ", age=" + age + ", id=" + id + "]";
  26. }
  27. public Cat(String name, int age, int id) {
  28. super();
  29. this.name = name;
  30. this.age = age;
  31. this.id = id;
  32. }
  33. public Cat() {
  34. super();
  35. // TODO Auto-generated constructor stub
  36. }
  37. @Override
  38. public int hashCode() {
  39. final int prime = 31; //系数 31*1+5 * 31+1 11111
  40. int result = 1;
  41. result = prime * result + age;
  42. result = prime * result + id;
  43. result = prime * result + ((name == null) ? 0 : name.hashCode());
  44. return result;
  45. }
  46. @Override
  47. public boolean equals(Object obj) {
  48. if (this == obj)
  49. return true;
  50. if (obj == null)
  51. return false;
  52. if (getClass() != obj.getClass())
  53. return false;
  54. Cat other = (Cat) obj;
  55. if (age != other.age)
  56. return false;
  57. if (id != other.id)
  58. return false;
  59. if (name == null) {
  60. if (other.name != null)
  61. return false;
  62. } else if (!name.equals(other.name))
  63. return false;
  64. return true;
  65. }
  66. }

CatComparator

  1. package com.vince;
  2. import java.util.Comparator;
  3. public class CatComparator implements Comparator<Cat> {
  4. @Override
  5. public int compare(Cat o1, Cat o2) {
  6. return o1.getAge()-o2.getAge();
  7. }
  8. }

4、 集合框架Iterator接口

(1)集合输出

前面我们已经学习了集合的基本操作, 很多情况下, 我们需要把集合的内容进行输出, 也就是遍历集合。

遍历集合的方式有以下几种:

  1. Iterator
  2. ListIterator
  3. Enumeration
  4. foreach

其中Iterator的使用率最高, 在JDK1.5后新增的foreach也被大量使用。

(2)Iterator接口

  1. public interface Iterator<E>

对 collection 进行迭代的迭代器。 迭代器取代了 Java Collections Framework 中的 Enumeration。

9、集合 - 图1

(3)ListIterator

  1. public interface ListIterator<E>
  2. extends Iterator<E>

系列表迭代器, 允许程序员按任一方向遍历列表、 迭代期间修改列表, 并获得迭代器在列表中的当前位置

9、集合 - 图2

(4)Enumeration

  1. public interface Enumeration<E>

实现 Enumeration 接口的对象, 它生成一系列元素, 一次生成一个。 连续调用nextElement 方法将返回一系列的连续元素。

注: 此接口的功能与 Iterator 接口的功能是重复的。 此外, Iterator 接口添加了一个可选的移除操作, 并使用较短的方法名。 新的实现应该优先考虑使用 Iterator 接口而不是Enumeration 接口。

9、集合 - 图3

(5)forEach

在前面的知识讲解中, 我们使用forEach来输出数组的内容, 那么也可以输出集合中的内容。 在使用forEach输出的时候一定要注意的是, 创建集合时要指定操作泛型的类型。

  1. List<Integer> numbers = new ArrayList<>();

JDK1.8新特性:

  1. //no.1
  2. numbers.forEach((Integer integer) -> {System.out.println(integer);});
  3. //no.2
  4. numbers.forEach(integer -> {System.out.println(integer);});
  5. //no.3
  6. numbers.forEach(integer -> System.out.println(integer));
  7. //no.4
  8. numbers.forEach(System.out::println);
  9. //no.5
  10. numbers.forEach(new MyConsumer());

IteratorDemo

  1. import java.util.ArrayList;
  2. import java.util.Arrays;
  3. import java.util.Collection;
  4. import java.util.Enumeration;
  5. import java.util.Iterator;
  6. import java.util.List;
  7. import java.util.Vector;
  8. import java.util.function.Function;
  9. import java.util.function.Predicate;
  10. import java.util.function.Supplier;
  11. /**
  12. * 集合的输出(迭代)
  13. * @description
  14. */
  15. public class IteratorDemo {
  16. //断言接口
  17. private static void predicateTest(){
  18. List<String> list = Arrays.asList("Larry", "Moe", "Curly","Tom","QF_vince");
  19. List<String> result = filter(list,(s)->s.contains("o"));
  20. result.forEach(System.out::println);
  21. }
  22. private static List<String> filter(List<String> list,Predicate<String> p){
  23. List<String> results = new ArrayList<>();
  24. for (String s : list) {
  25. if(p.test(s)){ //测试是否符合要求
  26. results.add(s);
  27. }
  28. }
  29. return results;
  30. }
  31. //Supplier 代表结果供应商
  32. private static void supplierTest(){
  33. List<Integer> list = getNums(10,()->(int)(Math.random() * 100));
  34. list.forEach(System.out::println);
  35. }
  36. private static List<Integer> getNums(int num,Supplier<Integer> sup){
  37. List<Integer> list = new ArrayList<>();
  38. for(int i=0;i<num;i++){
  39. list.add(sup.get());
  40. }
  41. return list;
  42. }
  43. //Function表示接受一个参数并产生结果的函数
  44. private static void functionTest(){
  45. String s = strToUpp("qf_vince",(str)->str.toUpperCase());
  46. System.out.println(s);
  47. }
  48. public static String strToUpp(String str,Function<String,String> f){
  49. return f.apply(str);
  50. }
  51. /**
  52. * JDK1.8新的迭代方法
  53. */
  54. private static void foreach(){
  55. List<String> list = new ArrayList<>();
  56. list.add("tom");
  57. list.add("jack");
  58. list.add("job");
  59. list.add("lily");
  60. //Consumer
  61. list.forEach(s->System.out.println(s));
  62. //list.forEach(System.out::println);
  63. }
  64. private static void enumeration(){
  65. Vector<String> vs = new Vector<>();
  66. vs.add("tom");
  67. vs.add("jack");
  68. vs.add("bob");
  69. vs.add("lily");
  70. Enumeration<String> es = vs.elements();
  71. while(es.hasMoreElements()){
  72. System.out.println(es.nextElement());
  73. }
  74. }
  75. //foreach(1.5后)
  76. private static void foreach(Collection<Cat> c){
  77. for(Cat cat: c){
  78. System.out.println(cat);
  79. }
  80. }
  81. //iterator(1.5之前统一的迭代集合方式)
  82. private static void iterator(Collection<Cat> c){
  83. Iterator<Cat> iter = c.iterator();
  84. while(iter.hasNext()){
  85. System.out.println(iter.next());
  86. }
  87. }
  88. public static void main(String[] args) {
  89. List<Cat> list = new ArrayList<>();
  90. Cat c1 = new Cat("miaomiao",5,1);
  91. Cat c2 = new Cat("huahua",2,2);
  92. Cat c3 = new Cat("tom",5,3);
  93. Cat c4 = new Cat("miaomiao",3,1);
  94. list.add(c1);
  95. list.add(c2);
  96. list.add(c3);
  97. list.add(c4);
  98. // iterator(list);
  99. // foreach(list);
  100. // enumeration();
  101. // foreach();
  102. // functionTest();
  103. // supplierTest();
  104. // predicateTest();
  105. String[] strs={"ni","hao","aho","oerh"};
  106. List<String> li=Arrays.asList(strs); //使用Arrays.asList()制作的集合,其长度一定不能增加,故要将其转换
  107. // List<String> li=Arrays.asList("ni","hao","aho","oerh");
  108. ArrayList<String> li1=new ArrayList<>(li);
  109. li1.add("qwe");
  110. li1.forEach(System.out::println);
  111. List<String> li2=new ArrayList<>();
  112. for(String str:li1){
  113. if(str.contains("o")){
  114. li2.add(str);
  115. }
  116. }
  117. li2.forEach(System.out::println);
  118. }
  119. }

5、 JDK1.8新特性

Consumer接口 消费者接口

Function 接口 表示接受一个参数并产生结果的函数。

Supplier接口 代表结果供应商。

Predicate接口 断言接口

(1)Stream概念

Stream是元素的集合, 这点让Stream看起来有些类似Iterator;

可以支持顺序和并行的对原Stream进行汇聚的操作;

我们可以把Stream当成一个高级版本的Iterator。 原始版本的Iterator, 用户只能一个一个的遍历元素并对其执行某些操作; 高级版本的Stream, 用户只要给出需要对其包含的元素执行什么操作, 比如“ 过滤掉长度大于10的字符串” 、 “ 获取每个字符串的首字母”等, 具体这些操作如何应用到每个元素上, 就给Stream就好了!

(2)Stream常见操作

9、集合 - 图4

  1. import java.util.ArrayList;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.Optional;
  5. import java.util.stream.Collectors;
  6. import java.util.stream.Stream;
  7. /**
  8. * Stream接口:不是存储数据结构,数据源可以是一个集合,为了函数式编程创造 ,
  9. * 惰式执行,数据只能被消费一次
  10. *
  11. * 两种类型的操作方法:
  12. * 1、中间操作(生成一个Stream)
  13. * 2、结束操作(执行计算操作)
  14. * @description
  15. */
  16. public class StreamDemo {
  17. public static void main(String[] args) {
  18. Stream<String> stream = Stream.of("good","good","study","day","day","up");
  19. //foreach方法
  20. //stream.forEach((str)->System.out.println(str));
  21. //stream.forEach(System.out::println);
  22. //filter 过滤
  23. //stream.filter((s)->s.length()>3).forEach(System.out::println);
  24. //distinct 去重
  25. //stream.distinct().forEach(s->System.out.println(s));
  26. //map 映射
  27. //stream.map(s->s.toUpperCase()).forEach(s->System.out.println(s));
  28. //flatMap 展平
  29. // Stream<List<Integer>> ss = Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5));
  30. // ss.flatMap(list->list.stream()).forEach(System.out::println);
  31. //reduce 归纳
  32. // Optional<String> opt = stream.reduce((s1,s2)->s1.length()>=s2.length()?s1:s2);
  33. // System.out.println(opt.get());
  34. //collect 将stream转为List
  35. // List<String> list = stream.collect(Collectors.toList());
  36. // list.forEach(s->System.out.println(s));
  37. //集合转为流,筛选后,再转为数组
  38. //数组转为流,获取最小值
  39. List<Integer> li=Arrays.asList(1,5,4,2,3);
  40. Integer[] integers = li.stream().filter(s -> s > 2).toArray(Integer[]::new);
  41. Optional<Integer> reduce = Arrays.stream(integers).reduce((s1, s2) -> (s1 > s2 ? s1 : s2));
  42. System.out.println(reduce.get());
  43. //排序后转为数组
  44. Integer[] integers1 = li.stream().sorted().toArray(Integer[]::new);
  45. //:: 方法引用
  46. //引用静态方法 Integer::valueOf
  47. //引用对象的方法 list::add
  48. //引用构造方法 ArrayList::new
  49. }
  50. }

6、 集合框架Map接口

(1)Map接口

  1. public interface Map<K,V>

将键映射到值的对象, 一个映射不能包含重复的键; 每个键最多只能映射到一个值。

9、集合 - 图5

9、集合 - 图6

(2)HashMap

  1. public class HashMap<K,V> extends AbstractMap<K,V>
  2. implements Map<K,V>, Cloneable, Serializable

基于哈希表的 Map 接口的实现。 此实现提供所有可选的映射操作, 并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外, HashMap 类与 Hashtable 大致相同。 ) 此类不保证映射的顺序, 特别是它不保证该顺序恒久不变

(3)Hashtable

  1. public class Hashtable<K,V> extends Dictionary<K,V>
  2. implements Map<K,V>, Cloneable, Serializable

此类实现一个哈希表, 该哈希表将键映射到相应的值。 任何非 null 对象都可以用作键或值。

为了成功地在哈希表中存储和获取对象, 用作键的对象必须实现 hashCode 方法和 equals 方法

(4)LinkedHashMap

  1. public class LinkedHashMap<K,V>
  2. extends HashMap<K,V> implements Map<K,V>

Map 接口的哈希表和链接列表实现, 具有可预知的迭代顺序。 此实现与 HashMap 的不同之处在于, 后者维护着一个运行于所有条目的双重链接列表。

(5)TreeMap

  1. public class TreeMap<K,V> extends AbstractMap<K,V>
  2. implements NavigableMap<K,V>, Cloneable, Serializable

基于红黑树(Red-Black tree) 的 NavigableMap 实现。 该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序, 具体取决于使用的构造方法。

(6)1.8 Map接口的新方法

在JDK8中Map接口提供了一些新的便利的方法。 因为在本文中我所提到的所有Map方法都是以默认值方法的方式实现的, 所以现有的Map接口的实现可以直接拥有这些在默认值方法中定义的默认行为, 而不需要新增一行代码。

  • getOrDefault(Object, V)
  • putIfAbsent(K,V)
  • remove(Object key, Object value)
  • replace(K,V)
  • replace(K,V,V)
  • compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
  • computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
  • merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)

MapDemo

  1. package com.vince;
  2. import java.util.Collection;
  3. import java.util.HashMap;
  4. import java.util.Hashtable;
  5. import java.util.LinkedHashMap;
  6. import java.util.Map;
  7. import java.util.Map.Entry;
  8. import java.util.Set;
  9. import java.util.TreeMap;
  10. /**
  11. * Map接口:
  12. * 1、键值对存储一组对象
  13. * 2、Key不能重复(唯一),Value可以重复
  14. * 3、具体的实现类:HashMap TreeMap Hashtable LinkedHashMap
  15. * 4、HashMap 与 Hashtable的区别?
  16. * 5、如何选择使用哪个?
  17. * 排序且选择二叉树存储:TreeMap
  18. * 不要求排序且单线程:HashMap
  19. * 多线程:Hashtable
  20. * 保证顺序;LinkedHashMap
  21. * 6、数据结构:数组、链表、二叉树(红黑树)、哈希表(数组+链表)、栈、队列
  22. * @description
  23. */
  24. public class MapDemo {
  25. /**
  26. * 基于二叉树的红黑树实现
  27. */
  28. private static void treeMap(){
  29. Map<String,String> map = new TreeMap<>();
  30. // map.put("one", "Lily");
  31. // map.put("two", "Tom");
  32. // map.put("three", "Bin");
  33. // map.forEach((key,value)->System.out.println(key+"->"+value));
  34. //
  35. Map<Dog,String> dogs = new TreeMap<>();
  36. dogs.put(new Dog(1,"2ha",3), "dog1");
  37. dogs.put(new Dog(1,"wangwang",2), "dog2");
  38. dogs.put(new Dog(3,"hsq",4), "dog3");
  39. dogs.forEach((key,value)->System.out.println(key+"->"+value));
  40. }
  41. /**
  42. * LinkedHashMap是HashMap的子类,由于HashMap不能保正顺序恒久不变,此类使用一个双重链表来维护
  43. * 元素添加的顺序。
  44. */
  45. private static void linkedHashMap(){
  46. Map<String,String> table = new LinkedHashMap<>();
  47. table.put("one", "Lily");
  48. table.put("two", "Tom");
  49. table.put("three", "Bin");
  50. table.forEach((key,value)->System.out.println(key+"->"+value));
  51. }
  52. /**
  53. * JDK1.0开始
  54. * 基于哈希表实现(数组+链表)
  55. * 默认数组大小为11,加载因子0.75
  56. * 扩充方式:原数组大小<<1 (*2) +1
  57. * 线程安全的,用在多线程访问时
  58. */
  59. private static void hashtable(){
  60. Map<String,String> table = new Hashtable<>();
  61. table.put("one", "Lily");
  62. table.put("two", "Tom");
  63. table.put("three", "Bin");
  64. table.forEach((key,value)->System.out.println(key+"->"+value));
  65. }
  66. /**
  67. * HashMap的现实原理:
  68. * 1、基于哈希表(数组+链表+二叉树(红黑树))1.8JDK
  69. * 2、默认加载因子为0.75,默认数组大小是16,加载因子含义:如果空间的75%被存满,则该数组空间已经被存满
  70. * 3、把对象存储到哈希表中,如何存储?
  71. * 把key对象通过hash()方法计算hash值,然后用这个hash值对数组长度取余数(默认16),来决定该对KEY对象
  72. * 在数组中存储的位置 ,当这个位置 有多个对象时,以链表结构存储,JDK1.8后,当链表长度大于8时,链表将转换为
  73. * 红黑树结构存储。
  74. * 这样的目的,是为了取值更快,存储的数据量越大,性能的表现越明显
  75. * 4、扩充原理:当数组的容量超过了75%,那么表示该数组需要扩充,如何扩充?
  76. * 扩充的算法是:当前数组容量<<1 (相当于是乘2),扩大1倍, 扩充次数过多,会影响性能,每次扩充表示哈希表重新
  77. * 散列(重新计算每个对象的存储位置),我们在开发中尽量要减少扩充次数带来的性能问题。
  78. * 5、线程不安全,适合在单线程中使用
  79. */
  80. private static void hashMap(){
  81. Map<Integer,String> map = new HashMap<>();
  82. map.put(1, "Tom");
  83. map.put(2, "Jack");
  84. map.put(3, "Vince");
  85. map.put(4, "Bin");
  86. map.put(5, "Lily");
  87. System.out.println("size="+map.size());
  88. //从MAP中取值
  89. System.out.println(map.get(1));//通过key取value
  90. //map的遍历
  91. //1 遍历Entry
  92. Set<Entry<Integer,String>> entrySet = map.entrySet();
  93. for(Entry e: entrySet){
  94. System.out.println(e.getKey()+"->"+e.getValue());
  95. }
  96. System.out.println("--------");
  97. //2 遍历键
  98. Set<Integer> keys = map.keySet();
  99. for(Integer i: keys){
  100. String value = map.get(i);
  101. System.out.println(i+"->"+value);
  102. }
  103. System.out.println("--------");
  104. //3 遍历值
  105. Collection<String> values = map.values();
  106. for(String value: values){
  107. System.out.println(value);
  108. }
  109. System.out.println("--------");
  110. //4 foreach
  111. Map<Integer,String> map1=new HashMap<>();
  112. map.forEach((key,value)->{
  113. if(key>3){
  114. map1.put(key+1,value);
  115. }
  116. });
  117. map1.forEach((key,value)->System.out.println(key+"->"+value));
  118. System.out.println(map.containsKey(7));
  119. //hash
  120. Integer key = 1434;
  121. System.out.println( 1434 % 16 );
  122. }
  123. public static void main(String[] args) {
  124. hashMap();
  125. // hashtable();
  126. // treeMap();
  127. }
  128. }

Dog

  1. package com.vince;
  2. public class Dog implements Comparable<Dog>{
  3. private int id;
  4. private String name;
  5. private int age;
  6. public int getId() {
  7. return id;
  8. }
  9. public void setId(int id) {
  10. this.id = id;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public Dog(int id, String name, int age) {
  25. super();
  26. this.id = id;
  27. this.name = name;
  28. this.age = age;
  29. }
  30. public Dog() {
  31. super();
  32. // TODO Auto-generated constructor stub
  33. }
  34. @Override
  35. public String toString() {
  36. return "Dog [id=" + id + ", name=" + name + ", age=" + age + "]";
  37. }
  38. @Override
  39. public int compareTo(Dog o) {
  40. return this.id-o.id;
  41. }
  42. }

MapNewMethodDemo

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. /**
  4. * Map接口1.8新增方法介绍
  5. * @description
  6. */
  7. public class MapNewMethodDemo {
  8. public static void main(String[] args) {
  9. Map<Integer,String> map = new HashMap<>();
  10. map.put(1, "jack");
  11. map.put(2, "tom");
  12. map.put(3, "lily");
  13. String value1 = map.getOrDefault(4, "null");
  14. System.out.println(value1);
  15. // String s = map.get(5);
  16. // if(s==null){
  17. // System.out.println();
  18. // }else{
  19. //
  20. // }
  21. String val = map.put(3,"vince");
  22. System.out.println(val); //返回以前的值
  23. map.forEach((key,value)-> System.out.println(key+"->"+value));
  24. //只会添加不存在相同key的值
  25. String val1 = map.putIfAbsent(3, "vince");
  26. System.out.println(val1);
  27. map.forEach((k,v)->System.out.println(k+"->"+v));
  28. //根据键和值都匹配时才删除
  29. map.remove(1, "jack");
  30. //替换map中的值
  31. map.replace(3, "vince");
  32. map.replace(3, "lily", "vince");
  33. //计算操作数据
  34. map.compute(1, (k,v1)->v1+"1");
  35. map.computeIfAbsent(5,(val2)->val2+"test");
  36. //合并
  37. map.merge(8, "888", (oldVal,newVal)->oldVal.concat(newVal));
  38. map.forEach((k,v)->System.out.println(k+"->"+v));
  39. }
  40. }

7、 Collections工具类

Collections类

Collections工具类提供了大量针对Collection/Map的操作, 总体可分为四类, 都为静态(static) 方法:

(1)排序操作(主要针对List接口相关)

  1. reverse(List list): 反转指定List集合中元素的顺序
  2. shuffle(List list): 对List中的元素进行随机排序(洗牌)
  3. sort(List list): 对List里的元素根据自然升序排序
  4. sort(List list, Comparator c): 自定义比较器进行排序
  5. swap(List list, int i, int j): 将指定List集合中i处元素和j出元素进行交换
  6. rotate(List list, int distance): 将所有元素向右移位指定长度, 如果distance等于size那么结果不变

(2)查找和替换(主要针对Collection接口相关)

  1. binarySearch(List list, Object key): 使用二分搜索法, 以获得指定对象在List中的索引, 前提是集合已经排序
  2. max(Collection coll): 返回最大元素
  3. max(Collection coll, Comparator comp): 根据自定义比较器, 返回最大元素
  4. min(Collection coll): 返回最小元素
  5. min(Collection coll, Comparator comp): 根据自定义比较器, 返回最小元素
  6. fill(List list, Object obj): 使用指定对象填充
  7. frequency(Collection Object o): 返回指定集合中指定对象出现的次数
  8. replaceAll(List list, Object old, Object new): 替换

(3)同步控制

Collections工具类中提供了多个synchronizedXxx方法, 该方法返回指定集合对象对应的同步对象, 从而解决多线程并发访问集合时线程的安全问题。 HashSet、 ArrayList、 HashMap都是线程不安全的, 如果需要考虑同步,则使用这些方法。 这些方法主要有: synchronizedSet、 synchronizedSortedSet、 synchronizedList、synchronizedMap、 synchronizedSortedMap

特别需要指出的是, 在使用迭代方法遍历集合时需要手工同步返回的集合

(4)设置不可变集合

Collections有三类方法可返回一个不可变集合:

  1. emptyXxx(): 返回一个空的不可变的集合对象
  2. singletonXxx(): 返回一个只包含指定对象的, 不可变的集合对象。
  3. unmodifiableXxx(): 返回指定集合对象的不可变视图

(5)其它

  1. disjoint(Collection c1, Collection c2) - 如果两个指定 collection 中没有相同的元素, 则返回 true。
  2. addAll(Collection<? super T> c, T… a) - 一种方便的方式, 将所有指定元素添加到指定 collection 中。
  3. Comparator reverseOrder(Comparator cmp) - 返回一个比较器, 它强行反转指定比较器的顺序。 如果指定比较器为 null, 则此方法等同于 reverseOrder()(换句话说, 它返回一个比较器, 该比较器将强行反转实现Comparable 接口那些对象 collection 上的自然顺序)。
  1. import java.util.ArrayList;
  2. import java.util.Collections;
  3. import java.util.List;
  4. /**
  5. * Collections工具类
  6. * @description
  7. */
  8. public class CollectionsDemo {
  9. public static void main(String[] args) {
  10. List<String> list = new ArrayList<>();
  11. list.add("jack");
  12. list.add("tom");
  13. list.add("lily");
  14. list.add("lily");
  15. System.out.println(list); //[jack, tom, lily, lily]
  16. //(1)排序操作
  17. //反转数组
  18. // Collections.reverse(list); //[lily, lily, tom, jack]
  19. //随机排序
  20. // Collections.shuffle(list); //[lily, lily, jack, tom]
  21. //sort按自然的升序排序
  22. // Collections.sort(list); //[jack, lily, lily, tom]
  23. //再多传一个排序对象
  24. // Collections.sort(list, c);
  25. //交换两个值
  26. // Collections.swap(list, 0, 2); //[lily, tom, jack, lily]
  27. //旋转,将所有元素向右移动指定位置
  28. // Collections.rotate(list, 1); //[lily, jack, tom, lily]
  29. //(2)查找替换
  30. //找某个值
  31. // System.out.println(Collections.binarySearch(list, "tom")); //1
  32. //返回最大值
  33. // System.out.println(Collections.max(list)); //tom
  34. //返回最小值
  35. // System.out.println(Collections.min(list)); //jack
  36. //填充
  37. // Collections.fill(list, "bin"); //[bin, bin, bin, bin]
  38. //返回集合中指定对象出现的次数
  39. // System.out.println(Collections.frequency(list, "lily")); //2
  40. //替换
  41. // Collections.replaceAll(list, "lily", "bin"); //[jack, tom, bin, bin]
  42. //(3)同步控制
  43. // List<String> syncList = Collections.synchronizedList(new ArrayList<String>());
  44. //(4)设置不可变集合
  45. // List<String> sList = Collections.emptyList();
  46. // sList.add("bin"); //会报错
  47. //(5)反转后排序:倒序
  48. // Collections.sort(list,Collections.reverseOrder()); //[tom, lily, lily, jack]
  49. }
  50. public static List<String> query(){
  51. List<String> list = null;
  52. //查不到,返回一个空集合
  53. return Collections.emptyList();
  54. }
  55. }

8、Optional容器类(JDK1.8)

Optional容器类(JDK1.8)

这是一个可以为null的容器对象。 如果值存在则isPresent()方法会返回true, 调用get()方法会返回该对象

  1. of:为非null的值创建一个Optional。
  2. ofNullable:为指定的值创建一个Optional, 如果指定的值为null, 则返回一个空的Optional。
  3. isPresent:如果值存在返回true, 否则返回false。
  4. get:如果Optional有值则将其返回, 否则抛出NoSuchElementException。
  5. ifPresent:如果Optional实例有值则为其调用consumer, 否则不做处理
  6. orElse:如果有值则将其返回, 否则返回指定的其它值
  7. orElseGet:orElseGet与orElse方法类似, 区别在于得到的默认值。 orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
  8. orElseThrow:如果有值则将其返回, 否则抛出supplier接口创建的异常。
  9. map:如果有值, 则对其执行调用mapping函数得到返回值。 如果返回值不为null, 则创建包含mapping返回值的Optional作为map方法返回值, 否则返回空Optional。
  10. flatMap:如果有值, 为其执行mapping函数返回Optional类型返回值, 否则返回空Optional。 flatMap与map(Funtion) 方法类似, 区别在于flatMap中的mapper返回值必须是Optional。 调用结束时,flatMap不会对结果用Optional封装。
  11. filter:如果有值并且满足断言条件返回包含该值的Optional, 否则返回空Optional
  1. package com.vince;
  2. import java.util.Optional;
  3. /**
  4. * Optional JDK1.8容器类
  5. * @description
  6. */
  7. public class OptionalDemo {
  8. public static void main(String[] args) {
  9. //创建Optional对象的方式
  10. Optional<String> optional = Optional.of("bin");
  11. // Optional<String> optional2 = Optional.ofNullable("bin");
  12. Optional<String> optional3 = Optional.empty();
  13. System.out.println(optional.isPresent()); //true
  14. System.out.println(optional.get()); //bin
  15. optional.ifPresent((value)->System.out.println(value)); //如果有值则调用 //bin
  16. System.out.println(optional.orElse("无值")); //如果有值则返回,否则返回其他值 //bin
  17. System.out.println(optional.orElseGet(()->"default")); //设定一个默认值 //bin
  18. // try {
  19. // optional3.orElseThrow(Exception::new);
  20. // } catch (Exception e) {
  21. // e.printStackTrace();
  22. // }
  23. Optional<String> optional4 = optional.map((value)->value.toUpperCase()); //BIN
  24. System.out.println(optional4.orElse("no found"));
  25. optional4 = optional.flatMap((value)->Optional.of(value.toUpperCase()+"-flatMap")); //BIN-flatMap
  26. System.out.println(optional4.orElse("no found"));
  27. optional4 = optional.filter((value)->value.length()>3); //这个值的长度小于3
  28. System.out.println(optional4.orElse("这个值的长度小于3"));
  29. }
  30. }

9、 Queue、Deque接口

队列(Queue) 是一种特殊的线性表, 是一种先进先出( FIFO) 的数据结构。 它只允许在表的前端( front) 进行删除操作, 而在表的后端( rear) 进行插入操作。 进行插入操作的端称为队尾, 进行删除操作的端称为队头。 队列中没有元素时, 称为空队列。

LinkedList是Queue接口的实现类

  1. boolean add(E e) : 将指定的元素插入此队列(如果立即可行且不会违反容量限制) , 在成功时返回 true, 如果当前没有可用的空间, 则抛出 IllegalStateException。
  2. E element() : 获取, 但是不移除此队列的头。
  3. boolean offer(E e) : 将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时, 此方法通常要优于 dd(E), 后者可能无法插入元素, 而只是抛出一个异常。
  4. E peek() : 获取但不移除此队列的头; 如果此队列为空, 则返回 null。
  5. E poll() : 获取并移除此队列的头, 如果此队列为空, 则返回 null。
  6. E remove() : 获取并移除此队列的头。

Deque: 一个线性 collection, 支持在两端插入和移除元素。

此接口既支持有容量限制的双端队列, 也支持没有固定大小限制的双端队列。

接口定义在双端队列两端访问元素的方法。 提供插入、 移除和检查元素的方法

  1. import java.util.Deque;
  2. import java.util.LinkedList;
  3. import java.util.Queue;
  4. import java.util.Stack;
  5. /**
  6. * Queue接口:队列,是一种先进先出的线性数据结构(排队)
  7. * LinkedList类实现了queue接口
  8. * 请求队列,消息队列,任务
  9. *
  10. * Deque接口:双端队列
  11. * Stack:堆栈 :先进后出
  12. * @description
  13. */
  14. public class QueueDequeDemo {
  15. private static void stack(){
  16. //堆栈:先进后出
  17. Stack<String> s = new Stack<>();
  18. //压栈
  19. s.push("Bin");
  20. s.push("Tom");
  21. s.push("Lily");
  22. System.out.println(s.pop()); //Lily
  23. System.out.println(s.peek()); //Tom
  24. System.out.println(s.pop()); //Tom
  25. System.out.println(s.pop()); //Bin
  26. }
  27. private static void deque(){
  28. //双端队列
  29. Deque<String> deque = new LinkedList<>();
  30. deque.add("小花");
  31. deque.add("小黑");
  32. deque.add("小小");
  33. deque.add("小白");
  34. deque.add("小丽");
  35. System.out.println(deque.getFirst()); //小花
  36. System.out.println(deque.getLast()); //小丽
  37. }
  38. private static void queue(){
  39. //队列:先进先出
  40. Queue<String> queue = new LinkedList<>();
  41. //往队列里添加元素
  42. queue.add("小花");
  43. queue.add("小黑");
  44. queue.add("小小");
  45. queue.add("小白");
  46. queue.add("小丽");
  47. //队列的长度大小
  48. System.out.println(queue.size()); //5
  49. //获取队列的头,但不移除,若为空返回null
  50. System.out.println(queue.peek()); //小花
  51. System.out.println(queue.size()); //5
  52. //获取队列的头,并删除
  53. System.out.println(queue.poll()); //小花
  54. System.out.println(queue.size()); //4
  55. System.out.println(queue);
  56. queue.offer("小明");
  57. System.out.println(queue);
  58. }
  59. public static void main(String[] args) {
  60. // queue();
  61. // deque();
  62. stack();
  63. }
  64. }

10、对象一对多与多对多关系

OneToManyDemo

  1. /**
  2. * 对象的一对多关系
  3. *
  4. * @description
  5. */
  6. public class OneToManyDemo {
  7. public static void main(String[] args) {
  8. Teacher t1 = new Teacher("张老师",18,"女");
  9. Student s1 = new Student("小李",10);
  10. Student s2 = new Student("小王",12);
  11. Student s3 = new Student("小赵",11);
  12. //关联关系
  13. t1.getStudents().add(s1);
  14. t1.getStudents().add(s2);
  15. t1.getStudents().add(s3);
  16. s1.setTeacher(t1);
  17. s2.setTeacher(t1);
  18. s3.setTeacher(t1);
  19. print(t1);
  20. }
  21. private static void print(Teacher t1) {
  22. System.out.println(t1.getName());
  23. // for(Student s: t1.getStudents()){
  24. // System.out.println(s);
  25. // }
  26. t1.getStudents().forEach(System.out::println);
  27. }
  28. }

Student

  1. /**
  2. *
  3. * @description
  4. */
  5. public class Student {
  6. private int sid;
  7. public int getSid() {
  8. return sid;
  9. }
  10. public void setSid(int sid) {
  11. this.sid = sid;
  12. }
  13. private String sname;
  14. private int age;
  15. private Teacher teacher;
  16. public Teacher getTeacher() {
  17. return teacher;
  18. }
  19. public void setTeacher(Teacher teacher) {
  20. this.teacher = teacher;
  21. }
  22. public String getSname() {
  23. return sname;
  24. }
  25. public void setSname(String sname) {
  26. this.sname = sname;
  27. }
  28. public int getAge() {
  29. return age;
  30. }
  31. public void setAge(int age) {
  32. this.age = age;
  33. }
  34. public Student(String sname, int age) {
  35. super();
  36. this.sname = sname;
  37. this.age = age;
  38. }
  39. public Student() {
  40. super();
  41. // TODO Auto-generated constructor stub
  42. }
  43. @Override
  44. public String toString() {
  45. return "Student [sname=" + sname + ", age=" + age + "]";
  46. }
  47. }

Teacher

  1. import java.util.HashSet;
  2. //一个老师对应多个学生
  3. public class Teacher {
  4. private String name;
  5. private int age;
  6. private String sex;
  7. private HashSet<Student> students = new HashSet<>();
  8. public HashSet<Student> getStudents() {
  9. return students;
  10. }
  11. public void setStudents(HashSet<Student> students) {
  12. this.students = students;
  13. }
  14. public String getName() {
  15. return name;
  16. }
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. public int getAge() {
  21. return age;
  22. }
  23. public void setAge(int age) {
  24. this.age = age;
  25. }
  26. public String getSex() {
  27. return sex;
  28. }
  29. public void setSex(String sex) {
  30. this.sex = sex;
  31. }
  32. @Override
  33. public String toString() {
  34. return "Teacher [name=" + name + ", age=" + age + ", sex=" + sex + "]";
  35. }
  36. public Teacher() {
  37. super();
  38. // TODO Auto-generated constructor stub
  39. }
  40. public Teacher(String name, int age, String sex) {
  41. super();
  42. this.name = name;
  43. this.age = age;
  44. this.sex = sex;
  45. }
  46. }

StudentAndCourse

  1. public class StudentAndCourse {
  2. private int id;
  3. private int sid;
  4. private int cid;
  5. public int getId() {
  6. return id;
  7. }
  8. public void setId(int id) {
  9. this.id = id;
  10. }
  11. public int getSid() {
  12. return sid;
  13. }
  14. public void setSid(int sid) {
  15. this.sid = sid;
  16. }
  17. public int getCid() {
  18. return cid;
  19. }
  20. public void setCid(int cid) {
  21. this.cid = cid;
  22. }
  23. }

11、迭代器设计模式

提供一个方法按顺序遍历一个集合内的元素, 而又不需要暴露该对象的内部表示。

应用场景:

  1. 访问一个聚合的对象, 而不需要暴露对象的内部表示
  2. 支持对聚合对象的多种遍历
  3. 对遍历不同的对象, 提供统一的接口

迭代器模式的角色构成:

  1. 迭代器角色(Iterator) :定义遍历元素所需要的方法, 一般来说会有这么三个方法: 取得下一个元素的方法next(), 判断是否遍历结束的方法hasNext(), 移出当前对象的方法remove()
  2. 具体迭代器角色(Concrete Iterator) : 实现迭代器接口中定义的方法, 完成集合的迭代
  3. 容器角色(Aggregate): 一般是一个接口, 提供一个iterator()方法, 例如java中的Collection接口,List接口, Set接口等
  4. 具体容器角色(ConcreteAggregate) : 就是抽象容器的具体实现类, 比如List接口的有序列表实现ArrayList, List接口的链表实现LinkedList, Set接口的哈希列表的实现HashSet等

Iterator

  1. package iterator;
  2. /**
  3. * 迭代器的接口
  4. * @description
  5. */
  6. public interface Iterator {
  7. public boolean hasNext();
  8. public Object next();
  9. }

ConcreteIterator

  1. package iterator;
  2. /**
  3. * 迭代器接口的具体实现类
  4. * @description
  5. */
  6. public class ConcreteIterator implements Iterator{
  7. private MyList list = null;
  8. private int index;//迭代器的指针
  9. public ConcreteIterator(MyList list) {
  10. this.list = list;
  11. }
  12. @Override
  13. public boolean hasNext() {
  14. if(index>=list.getSize())
  15. return false;
  16. else return true;
  17. }
  18. @Override
  19. public Object next() {
  20. Object obj = list.get(index);
  21. index++;
  22. return obj;
  23. }
  24. }

MyList

  1. package iterator;
  2. /**
  3. * 容器的接口
  4. * @description
  5. */
  6. public interface MyList {
  7. void add(Object e);
  8. Object get(int index);
  9. Iterator iterator();
  10. int getSize();
  11. }

ConcreteAggregate

  1. package iterator;
  2. /**
  3. * 容器接口的具体实现类
  4. * @description
  5. */
  6. public class ConcreteAggregate implements MyList{
  7. private Object[] elements;//对象数组
  8. private int size;
  9. private int index;
  10. public ConcreteAggregate() {
  11. elements = new Object[100];
  12. }
  13. @Override
  14. public void add(Object e) {
  15. elements[index++] = e;
  16. size++;
  17. }
  18. @Override
  19. public Object get(int index) {
  20. return elements[index];
  21. }
  22. @Override
  23. public Iterator iterator() {
  24. return new ConcreteIterator(this);
  25. }
  26. @Override
  27. public int getSize() {
  28. return size;
  29. }
  30. }

Test

  1. package iterator;
  2. /**
  3. * @description
  4. */
  5. public class Test {
  6. public static void main(String[] args) {
  7. MyList list = new ConcreteAggregate();
  8. list.add("刘备");
  9. list.add("张飞");
  10. list.add("关羽");
  11. list.add("曹操");
  12. list.add("诸葛亮");
  13. Iterator iter = list.iterator();
  14. while(iter.hasNext()){
  15. System.out.println(iter.next());
  16. }
  17. }
  18. }

12、guava对集合的支持

版本下载: https://repo1.maven.org/maven2/com/google/guava/guava/

Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, 例如: 集合 [collections] 、 缓存 [caching] 、 原生类型支持 [primitives support] 、 并发库 [concurrency libraries] 、 通用注解 [common annotations] 、 字符串处理 [string processing] 、 I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。

Guava对JDK集合的扩展, 这是Guava最成熟和为人所知的部分。

  1. 不可变集合: 用不变的集合进行防御性编程和性能提升。
  2. 新集合类型: multisets, multimaps, tables,等
  3. 强大的集合工具类: 提供java.util.Collections中没有的集合工具
  4. 扩展工具类: 让实现和扩展集合类变得更容易, 比如创建Collection的装饰器, 或实现迭代器

各种功能

  1. 只读设置
  2. 函数式编程:过滤器
  3. 函数式编程:转换
  4. 组合式函数编程
  5. 加入约束: 非空、 长度验证
  6. 集合操作: 交集、 差集、 并集
  7. Multiset: 无序可重复,可计算个数
  8. Multimap key可以重复
  9. BiMap: 双向Map(bidirectional Map) 键与值不能重复
  10. 双键的Map —>Table —->rowKey+columnKye+value
  1. package com.guava;
  2. import java.text.SimpleDateFormat;
  3. import java.util.*;
  4. import java.util.stream.Collectors;
  5. import com.google.common.collect.*;
  6. import org.junit.Test;
  7. import com.google.common.base.Function;
  8. import com.google.common.base.Functions;
  9. import com.google.common.collect.Sets.SetView;
  10. import com.google.common.collect.Table.Cell;
  11. public class GuavaDemo {
  12. //双键的Map -->Table --->rowKey+columnKye+value
  13. @Test
  14. public void testGuava10(){
  15. Table<String, String, Integer> table = HashBasedTable.create();
  16. table.put("jack", "java", 80);
  17. table.put("tom", "php", 70);
  18. table.put("bin", "java", 59);
  19. table.put("lily", "ui", 98);
  20. Set<Cell<String,String,Integer>> cells = table.cellSet();
  21. for(Cell c: cells){
  22. System.out.println(c.getRowKey()+"-"+c.getColumnKey()+"-"+c.getValue());
  23. }
  24. //jack-java-80
  25. //tom-php-70
  26. //bin-java-59
  27. //lily-ui-98
  28. }
  29. //BiMap:双向Map(bidirectional Map) 键与值不能重复
  30. @Test
  31. public void testGuava9(){
  32. BiMap<String, String> map = HashBiMap.create();
  33. map.put("finally_test", "18201583398");
  34. map.put("bin_test", "18388881521");
  35. String name = map.inverse().get("18201583398"); //通过value取key
  36. System.out.println(name);
  37. System.out.println(map.inverse().inverse()==map); //true
  38. }
  39. // Multimap:key可重复
  40. @Test
  41. public void testGuava8() {
  42. Map<String,String> map = new HashMap<>();
  43. map.put("Java从入门到精通", "bin");
  44. map.put("Android从入门到精通", "bin");
  45. map.put("PHP从入门到精通", "jack");
  46. map.put("笑看人生", "vince");
  47. Multimap<String, String> mmap = ArrayListMultimap.create();
  48. Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
  49. while(iter.hasNext()){
  50. Map.Entry<String, String> entry = iter.next();
  51. mmap.put(entry.getValue(), entry.getKey());
  52. }
  53. Set<String> keySet = mmap.keySet();
  54. for(String key: keySet){
  55. Collection<String> values = mmap.get(key);
  56. System.out.println(key+"->"+values);
  57. }
  58. //bin->[Java从入门到精通, Android从入门到精通]
  59. //vince->[笑看人生]
  60. //jack->[PHP从入门到精通]
  61. }
  62. // Multiset:无序可重复
  63. @Test
  64. public void testGuava7() {
  65. String s = "good good study day day up";
  66. String[] ss = s.split(" ");
  67. HashMultiset<String> set = HashMultiset.create();
  68. for (String str : ss) {
  69. set.add(str);
  70. }
  71. Set<String> set2 = set.elementSet();
  72. for (String str : set2) {
  73. System.out.println(str + ":" + set.count(str));
  74. }
  75. //study:1
  76. //up:1
  77. //good:2
  78. //day:2
  79. }
  80. // 集合操作:交集、差集、并集
  81. @Test
  82. public void testGuava6() {
  83. Set<Integer> set1 = Sets.newHashSet(1, 2, 3);
  84. Set<Integer> set2 = Sets.newHashSet(3, 4, 5);
  85. // 交集
  86. SetView<Integer> v1 = Sets.intersection(set1, set2);
  87. // v1.forEach(System.out::println);
  88. // 差集
  89. SetView<Integer> v2 = Sets.difference(set1, set2);
  90. // v2.forEach(System.out::println);
  91. // 并集
  92. SetView<Integer> v3 = Sets.union(set1, set2);
  93. v3.forEach(System.out::println);
  94. }
  95. /**
  96. * 加入约束:非空、长度验证
  97. */
  98. @Test
  99. public void testGuava5() {
  100. // Set<String> set = Sets.newHashSet();
  101. // 14版可用
  102. // Constraint<String> constraint = new Constraint<>(){
  103. // @Override
  104. // public String checkElement(String element){
  105. //
  106. // }
  107. // }
  108. //检查参数
  109. // Preconditions.checkArgument(expression);
  110. // Preconditions.checkNotNull(reference)
  111. }
  112. /**
  113. * 组合式函数
  114. */
  115. @Test
  116. public void testGuava4() {
  117. List<String> list = Lists.newArrayList("java", "php", "jack", "h5", "javascript");
  118. Function<String, String> f1 = new Function<String, String>() {
  119. @Override
  120. public String apply(String t) {
  121. return t.length() > 4 ? t.substring(0, 4) : t;
  122. }
  123. };
  124. Function<String, String> f2 = new Function<String, String>() {
  125. @Override
  126. public String apply(String t) {
  127. return t.toUpperCase();
  128. }
  129. };
  130. Function<String, String> f = Functions.compose(f1, f2);
  131. Collection<String> coll = Collections2.transform(list, f);
  132. coll.forEach(System.out::println);
  133. // System.out.println(list);
  134. // list=list.stream().filter((l)->(l.length()>=4)).map((l)->(l.toUpperCase())).collect(Collectors.toList());
  135. // System.out.println(list);
  136. }
  137. /**
  138. * 转换
  139. */
  140. @Test
  141. public void testGuava3() {
  142. Set<Long> timeSet = Sets.newHashSet(20121212L, 20170520L, 20160808L);
  143. Collection<String> timeCollect = Collections2.transform(timeSet,
  144. (e) -> new SimpleDateFormat("yyyy-MM-dd").format(e));
  145. timeCollect.forEach(System.out::println);
  146. }
  147. /**
  148. * 过滤器
  149. */
  150. @Test
  151. public void testGuava2() {
  152. List<String> list = Lists.newArrayList("java", "php", "jack", "h5", "javascript");
  153. Collection<String> result = Collections2.filter(list, (e) -> e.startsWith("j"));
  154. result.forEach(System.out::println);
  155. // List<String> li= Arrays.asList("java", "php", "jack", "h5", "javascript");
  156. // li= li.stream().filter((e) -> (e.startsWith("j"))).collect(Collectors.toList());
  157. // System.out.println(li);
  158. }
  159. /**
  160. * 设置 只读
  161. */
  162. @Test
  163. public void testGuava1() {
  164. System.out.println("test guava");
  165. // List<String> list = Arrays.asList("jack","tom","lily","bin");
  166. // list.add("vince");
  167. List<String> list = new ArrayList<>();
  168. list.add("jack");
  169. list.add("tom");
  170. list.add("lily");
  171. list.add("bin");
  172. //变为只读
  173. // List<String> readList = Collections.unmodifiableList(list);
  174. // readList.add("vince");
  175. //guava实现只读
  176. ImmutableList<String> iList = ImmutableList.of("jack","tom","lily","bin");
  177. iList.add("vince");
  178. }
  179. }