1.0.0 Summary
Tittle:【Java】-NO.16.EBook.4.Java.1.008-【疯狂Java讲义第3版 李刚】- 集合
Style:EBook
Series:Java
Since:2017-09-22
End:....
Total Hours:...
Degree Of Diffculty:2
Degree Of Mastery:2
Practical Level:2
Desired Goal:2
Archieve Goal:....
Gerneral Evaluation:...
Writer:kingdelee
Related Links:
http://www.cnblogs.com/kingdelee/
1.
1.Iterator在迭代的过程中,不允许添加/删除对象,可以修改对象
2.想要在迭代中过滤/删除某个元素,使用Predicate
public class PredicateTest { public static void main(String[] args) { // 创建一个集合 Collection books = new HashSet(); books.add(new String("轻量级Java EE企业应用实战")); books.add(new String("疯狂Java讲义")); books.add(new String("疯狂iOS讲义")); books.add(new String("疯狂Ajax讲义")); books.add(new String("疯狂Android讲义")); // 使用Lambda表达式(目标类型是Predicate)过滤集合 books.removeIf(ele -> ((String)ele).length() < 10); System.out.println(books); } }
public class PredicateTest2 { public static void main(String[] args) { // 创建books集合、为books集合添加元素的代码与前一个程序相同。 Collection books = new HashSet(); books.add(new String("轻量级Java EE企业应用实战")); books.add(new String("疯狂Java讲义")); books.add(new String("疯狂iOS讲义")); books.add(new String("疯狂Ajax讲义")); books.add(new String("疯狂Android讲义")); // 统计书名包含“疯狂”子串的图书数量 System.out.println(calAll(books , ele->((String)ele).contains("疯狂"))); // 统计书名包含“Java”子串的图书数量 System.out.println(calAll(books , ele->((String)ele).contains("Java"))); // 统计书名字符串长度大于10的图书数量 System.out.println(calAll(books , ele->((String)ele).length() > 10)); } public static int calAll(Collection books , Predicate p) { int total = 0; for (Object obj : books) { // 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件 if (p.test(obj)) { total ++; } } return total; } }
3.Stream提供了常用的几个数据流的操作
public class IntStreamTest { public static void main(String[] args) { IntStream is = IntStream.builder() .add(20) .add(13) .add(-2) .add(18) .build(); // 下面调用聚集方法的代码每次只能执行一个 System.out.println("is所有元素的最大值:" + is.max().getAsInt()); System.out.println("is所有元素的最小值:" + is.min().getAsInt()); System.out.println("is所有元素的总和:" + is.sum()); System.out.println("is所有元素的总数:" + is.count()); System.out.println("is所有元素的平均值:" + is.average()); System.out.println("is所有元素的平方是否都大于20:" + is.allMatch(ele -> ele * ele > 20)); System.out.println("is是否包含任何元素的平方大于20:" + is.anyMatch(ele -> ele * ele > 20)); // 将is映射成一个新Stream,新Stream的每个元素是原Stream元素的2倍+1 IntStream newIs = is.map(ele -> ele * 2 + 1); // 使用方法引用的方式来遍历集合元素 newIs.forEach(System.out::println); // 输出41 27 -3 37 } }
中间方法:
filter(Predicate predicate):
mapToXxxx(ToXxxFunction mapper):一对一进行转换
peek(Consumer action):
distinct()::
sorted():
limit(long maxSize)
末端方法:
forEach(Consumer action):
toArray():
min():
max():
count():
anyMatch(Predicate predicate)
findFirst():
findAny();
public class CollectionStream { public static void main(String[] args) { // 创建books集合、为books集合添加元素的代码与8.2.5小节的程序相同。 Collection books = new HashSet(); books.add(new String("轻量级Java EE企业应用实战")); books.add(new String("疯狂Java讲义")); books.add(new String("疯狂iOS讲义")); books.add(new String("疯狂Ajax讲义")); books.add(new String("疯狂Android讲义")); // 统计书名包含“疯狂”子串的图书数量 System.out.println(books.stream().filter(ele->((String)ele).contains("疯狂")).count()); // 输出4 // 统计书名包含“Java”子串的图书数量 System.out.println(books.stream().filter(ele->((String)ele).contains("Java") ).count()); // 输出2 // 统计书名字符串长度大于10的图书数量 System.out.println(books.stream().filter(ele->((String)ele).length() > 10).count()); // 输出2 // 先调用Collection对象的stream()方法将集合转换为Stream, // 再调用Stream的mapToInt()方法获取原有的Stream对应的IntStream books.stream().mapToInt(ele -> ((String)ele).length())// 调用forEach()方法遍历IntStream中每个元素 .forEach(System.out::println);// 输出8 11 16 7 8 List<Integer> list = new ArrayList<>(); list.add(1); list.add(3); list.add(3); list.add(2); list.add(4); list.add(4); list.add(5); list.add(5); list.add(5); System.out.println("--------1"); list.stream().filter(f -> f == 3).forEach(System.out::println); System.out.println("--------2"); list.stream().distinct().forEach(System.out::println); System.out.println("--------3"); list.stream().sorted().forEach(System.out::println); System.out.println("--------4"); System.out.println(list.stream().min((a, b) -> a - b).get()); System.out.println("--------5"); list.stream().limit(5).forEach(System.out::println); System.out.println(list.stream().count()); System.out.println(list.stream().anyMatch(a -> a == 5)); System.out.println(list.stream().findAny().get()); System.out.println(list.stream().findAny().get()); list.stream().mapToInt(a -> a*10).forEach(System.out::println); list.stream().map(a -> a * a).forEach(System.out::println); // list.stream().flatMap((a, b) -> a * b).forEach(System.out::println); } }
4. Set:
Set实际上就是Collection,只是不允许添加重复元素。
HashSet、TreeSet、EnumSet
4.1 HashSet:
Hash排序
非同步
可以存null
比较集合中的元素是否相等的充要条件是,对应的hashcode()与equals()都要相等
// 1.判断Set集合中两个对象相等的条件是,equals和hashcode都要一样。 // 类A的equals方法总是返回true,但没有重写其hashCode()方法 class A { public boolean equals(Object obj) { return true; } } // 类B的hashCode()方法总是返回1,但没有重写其equals()方法 class B { public int hashCode() { return 1; } } // 类C的hashCode()方法总是返回2,且重写其equals()方法总是返回true class C { public int hashCode() { return 2; } public boolean equals(Object obj) { return true; } } public class HashSetTest { public static void main(String[] args) { HashSet books = new HashSet(); // 分别向books集合中添加两个A对象,两个B对象,两个C对象 books.add(new A()); books.add(new A()); books.add(new B()); books.add(new B()); books.add(new C()); books.add(new C()); books.forEach(System.out::println); } } //com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.B@1 //com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.B@1 //com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.A@610455d6 //com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.C@2 //com.lee.test.java.ebook.crazy_java.u_8_container.c_8_3_set.A@511d50c0
// 1. HashSet查找/删除元素的时候,是根据hashcode去操作的,所以有规律的重写hashcode可以避免某个撞桶 class R { int count; int count2; public R(int count) { this.count = count; } public R(int count, int count2) { this.count = count; this.count2 = count2; } // public String toString() // { // return "R[count:" + count + "]"; // } @Override public String toString() { return "R{" + "count=" + count + ", count2=" + count2 + '}'; } public boolean equals(Object obj) { if(this == obj) return true; if (obj != null && obj.getClass() == R.class) { R r = (R)obj; return this.count == r.count; } return false; } public int hashCode() { return this.count; } } public class HashSetTest2 { public static void main(String[] args) { HashSet hs = new HashSet(); hs.add(new R(5, 1)); hs.add(new R(-3, 2)); hs.add(new R(9, 3)); hs.add(new R(-2, 4)); // 打印HashSet集合,集合元素没有重复 System.out.println(hs); // 取出第一个元素 Iterator it = hs.iterator(); R first = (R)it.next(); // 为第一个元素的count实例变量赋值 first.count = -3; // ① // 再次输出HashSet集合,集合元素有重复元素 System.out.println(hs); // 删除count为-3的R对象 hs.remove(new R(-3)); // ② // 可以看到被删除了一个R元素 System.out.println(hs); System.out.println("hs是否包含count为-3的R对象?" + hs.contains(new R(-3))); // 输出false System.out.println("hs是否包含count为-2的R对象?" + hs.contains(new R(-2))); // 输出false System.out.println("hs是否包含count为5的R对象?" + hs.contains(new R(5))); // 输出false } }
6.LinkHashSet:
LinkHashSet是HashSet的子类,根据hashcode决定存储位置,并通过链表维护元素次序使得元素插入有序。故可以有序的迭代读取元素。
7.TreeSet:
TreeSet是SortedSet接口的实现类,采用红黑树结构存储。排序规则:自然排序、自定义排序。
应注意:
7.1 TreeSet中的对象,应该是同一类型或者父子关系,且实现了Comapble接口。
7.2 TreeSet中的对象,应实现Comaprable接口,否则再加入第二个元素时,因为排序会调用Comaprable所以会报错。
7.3 TreeSet判断是否为同一对象,取决于compareTo()是否返回0
class A1 implements Comparable{ @Override public int compareTo(Object o) { return 0; } } class B1 extends A1{ } public class TreeSetErrorTest2 { public static void main(String[] args) { TreeSet ts = new TreeSet(); // 向TreeSet集合中添加两个对象 // ts.add(new String("疯狂Java讲义")); // ts.add(new Date()); // ① ts.add(new A1()); // ① ts.add(new B1()); // ① } }
// 1. 当Set中的对象影响compareTo的元素被修改后,对该对象的删除和查找都将失效,而其他未被修改的对象正常。故不宜修改。 class R2 implements Comparable { int count; public R2(int count) { this.count = count; } public String toString() { return "R[count:" + count + "]"; } // 重写equals方法,根据count来判断是否相等 public boolean equals(Object obj) { if (this == obj) { return true; } if(obj != null && obj.getClass() == R2.class) { R2 r = (R2)obj; return r.count == this.count; } return false; } // 重写compareTo方法,根据count来比较大小 public int compareTo(Object obj) { R2 r = (R2)obj; return count > r.count ? 1 : count < r.count ? -1 : 0; } } public class TreeSetTest3 { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new R2(5)); ts.add(new R2(-3)); ts.add(new R2(9)); ts.add(new R2(-2)); // 打印TreeSet集合,集合元素是有序排列的 System.out.println(ts); // ① // 取出第一个元素 R2 first = (R2)ts.first(); // 对第一个元素的count赋值 first.count = 20; // 取出最后一个元素 R2 last = (R2)ts.last(); // 对最后一个元素的count赋值,与第二个元素的count相同 last.count = -2; // 再次输出将看到TreeSet里的元素处于无序状态,且有重复元素 System.out.println(ts); // ② // 删除实例变量被改变的元素,删除失败 System.out.println(ts.remove(new R2(-2))); // ③ System.out.println(ts); // 删除实例变量没有被改变的元素,删除成功 System.out.println(ts.remove(new R2(5))); // ④ System.out.println(ts); } }
// 1.定制排序 class M { int age; public M(int age) { this.age = age; } public String toString() { return "M[age:" + age + "]"; } } public class TreeSetTest4 { public static void main(String[] args) { // 此处Lambda表达式的目标类型是Comparator TreeSet ts = new TreeSet((o1 , o2) -> { M m1 = (M)o1; M m2 = (M)o2; // 根据M对象的age属性来决定大小,age越大,M对象反而越小 return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0; }); ts.add(new M(5)); ts.add(new M(-3)); ts.add(new M(9)); System.out.println(ts); } }
8.EmunSet
EmunSet
enum Season { SPRING,SUMMER,FALL,WINTER } public class EnumSetTest { public static void main(String[] args) { // 创建一个EnumSet集合,集合元素就是Season枚举类的全部枚举值 EnumSet es1 = EnumSet.allOf(Season.class); System.out.println(es1); // 输出[SPRING,SUMMER,FALL,WINTER] // 创建一个EnumSet空集合,指定其集合元素是Season类的枚举值。 EnumSet es2 = EnumSet.noneOf(Season.class); System.out.println(es2); // 输出[] // 手动添加两个元素 es2.add(Season.WINTER); es2.add(Season.SPRING); es2.add(Season.SPRING); System.out.println(es2); // 输出[SPRING,WINTER] // 以指定枚举值创建EnumSet集合 EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER); System.out.println(es3); // 输出[SUMMER,WINTER] EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER); System.out.println(es4); // 输出[SUMMER,FALL,WINTER] // 新创建的EnumSet集合的元素和es4集合的元素有相同类型, // es5的集合元素 + es4集合元素 = Season枚举类的全部枚举值 EnumSet es5 = EnumSet.complementOf(es4); System.out.println(es5); // 输出[SPRING] } }
public class EnumSetTest2 { public static void main(String[] args) { Collection c = new HashSet(); c.clear(); c.add(Season.FALL); c.add(Season.SPRING); // 复制Collection集合中所有元素来创建EnumSet集合 EnumSet enumSet = EnumSet.copyOf(c); // ① System.out.println(enumSet); // 输出[SPRING,FALL] c.add("疯狂Java讲义"); c.add("轻量级Java EE企业应用实战"); // 下面代码出现异常:因为c集合里的元素不是全部都为枚举值 enumSet = EnumSet.copyOf(c); // ② } }
各种Set的实现类比较:
8.1.在add(), get()操作,性能 HashSet > TreeSet,理由TreeSet需要额外的红黑树来维持次序。
8.2.在add(), delete()操作,性能 HashSet > LinkedHashSet,遍历操作,性能 HashSet < LinkedHashSet,理由 LinkedHashSet有链表维护次序。
8.3,EnumSet是性能最好的,只能保存同一种枚举类的值作为集合元素。
8.4.HashSet,TreeSet,EnumSet都不是线程安全的,同步时应使用类似:
TreeSet<Object> objects = new TreeSet<>();
Collections.synchronizedNavigableSet(objects);
9. List
1.根据元素的equals判断List中两个元素是否相等,如果重写某元素equals=true,则该元素与集合中的任意一元素恒等。
// 1.根据元素的equals判断List中两个元素是否相等,如果重写某元素equals=true,则该元素与集合中的任意一元素恒等。 class A { public boolean equals(Object obj) { return true; } } public class ListTest2 { public static void main(String[] args) { List books = new ArrayList(); books.add(new String("轻量级Java EE企业应用实战")); books.add(new String("疯狂Java讲义")); books.add(new String("疯狂Android讲义")); System.out.println(books); // 删除集合中A对象,将导致第一个元素被删除 books.remove(new A()); // ① System.out.println(books); // 删除集合中A对象,再次删除集合中第一个元素 books.remove(new A()); // ② System.out.println(books); } } //[轻量级Java EE企业应用实战, 疯狂Java讲义, 疯狂Android讲义] //[疯狂Java讲义, 疯狂Android讲义] //[疯狂Android讲义]
public class ListTest3 { public static void main(String[] args) { List books = new ArrayList(); // 向books集合中添加4个元素 books.add(new String("轻量级Java EE企业应用实战")); books.add(new String("疯狂Java讲义")); books.add(new String("疯狂Android讲义")); books.add(new String("疯狂iOS讲义")); // 使用目标类型为Comparator的Lambda表达式对List集合排序 // [疯狂iOS讲义, 疯狂Java讲义, 疯狂Android讲义, 轻量级Java EE企业应用实战] // books.sort((o1, o2)->((String)o1).length() - ((String)o2).length()); // [轻量级Java EE企业应用实战, 疯狂Android讲义, 疯狂Java讲义, 疯狂iOS讲义] // books.sort((o1, o2)->((String)o2).length() - ((String)o1).length()); // [疯狂iOS讲义, 疯狂Java讲义, 疯狂Android讲义, 轻量级Java EE企业应用实战] books.sort(Comparator.comparing(String::length)); System.out.println(books); // 使用目标类型为UnaryOperator的Lambda表达式来替换集合中所有元素 // 该Lambda表达式控制使用每个字符串的长度作为新的集合元素 books.replaceAll(ele->((String)ele).length()); System.out.println(books); // 输出[7, 8, 11, 16] } }
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
// 1. Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。 public class ListIteratorTest { public static void main(String[] args) { String[] books = { "疯狂Java讲义", "疯狂iOS讲义", "轻量级Java EE企业应用实战" }; List bookList = new ArrayList(); for (int i = 0; i < books.length ; i++ ) { bookList.add(books[i]); } ListIterator lit = bookList.listIterator(); while (lit.hasNext()) { System.out.println(lit.next()); lit.add("-------分隔符-------"); } System.out.println("=======下面开始反向迭代======="); while(lit.hasPrevious()) { System.out.println(lit.previous()); } } }
10. Vector Stack ArrayList ArrayDeque
10.1 Vector是线程安全的,ArrayList是线程不安全的,然而,要保证线程安全,只需使用Collections.synchronizedList()即可,故Vector没卵用。
10.2 Vector是古老的类,存在诸多缺点,性能低下,远不如ArrayList,所以Vector应不使用。
10.3 Stack是Vector的子类,模拟实现栈结构,然而远不如ArrayDeque,故Stack应不使用。
10.4 特别注意 Arrays.ArrayList返回的是一个固定长度的数组,是Arrays里边的一个静态内部类,不是util包的ArrayList,故不能使用add remove等方法。
11. Queue
11.1 队列不允许随机访问,使用的是FIFO(先进先出)策略操作存储。
11.2 Deque是双端队列的接口,可以使用实现类ArrayDeqeue LinkedList同时操作两端,ArrayDeqeue既是队列也是栈。
11.3 PriorityQueue,queue中的异端,采取元素的大小而非FIFO的策略进行存储。
对于ArrayDeque:
入栈:
push、addFirst :加头,无返回,null会异常。
offerFirst:加头,有返回值,null会异常。调用addFirst。
add:加头,返回boolean,null会异常。
offer、offerLast:加尾,返回boolean,null会异常。
出栈:
pop、removeFirst:取头,删除。null会异常。
peek、peekFirst:取头,不删除。null返null。
peekLast:取尾,不删除。null返null
public class PriorityQueueTest { public static void main(String[] args) { PriorityQueue pq = new PriorityQueue(); // 下面代码依次向pq中加入四个元素 pq.offer(6); pq.offer(-3); pq.offer(20); pq.offer(18); // 输出pq队列,并不是按元素的加入顺序排列 System.out.println(pq); // 输出[-3, 6, 20, 18] // 访问队列第一个元素,其实就是队列中最小的元素:-3 System.out.println(pq.poll()); } } public class LinkedListTest { public static void main(String[] args) { LinkedList books = new LinkedList(); // 将字符串元素加入队列的尾部 books.offer("疯狂Java讲义"); // 将一个字符串元素加入栈的顶部 books.push("轻量级Java EE企业应用实战"); // 将字符串元素添加到队列的头部(相当于栈的顶部) books.offerFirst("疯狂Android讲义"); // 以List的方式(按索引访问的方式)来遍历集合元素 for (int i = 0; i < books.size() ; i++ ) { System.out.println("遍历中:" + books.get(i)); } // 访问、并不删除栈顶的元素 System.out.println(books.peekFirst()); // 访问、并不删除队列的最后一个元素 System.out.println(books.peekLast()); // 将栈顶的元素弹出“栈” System.out.println(books.pop()); // 下面输出将看到队列中第一个元素被删除 System.out.println(books); // 访问、并删除队列的最后一个元素 System.out.println(books.pollLast()); // 下面输出:[轻量级Java EE企业应用实战] System.out.println(books); } } public class ArrayDequeStack { public static void main(String[] args) { ArrayDeque stack = new ArrayDeque(); // 依次将三个元素push入"栈" stack.push("1"); // stack.push("3"); // stack.push("4"); // stack.push("2"); // stack.push("5"); // add与Off是一样的方法 stack.addFirst("8"); stack.offer("8"); stack.add("8"); stack.addFirst("8"); stack.addLast("8"); stack.offer("8"); // System.out.println(stack); System.out.println(stack.peekLast()); System.out.println(stack.pop()); System.out.println(stack.peekLast()); System.out.println(stack); } } public class ArrayDequeQueue { public static void main(String[] args) { ArrayDeque queue = new ArrayDeque(); // 依次将三个元素加入队列 queue.offer("疯狂Java讲义"); queue.offer("轻量级Java EE企业应用实战"); queue.offer("疯狂Android讲义"); // 输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义] System.out.println(queue); // 访问队列头部的元素,但并不将其poll出队列"栈",输出:疯狂Java讲义 System.out.println(queue.peek()); // 依然输出:[疯狂Java讲义, 轻量级Java EE企业应用实战, 疯狂Android讲义] System.out.println(queue); // poll出第一个元素,输出:疯狂Java讲义 System.out.println(queue.poll()); // 输出:[轻量级Java EE企业应用实战, 疯狂Android讲义] System.out.println(queue); } }
12. ArrayList LinkedList
ArrayList 基于数组的线性表,以一块连续内存区保存所有元素,具有较好的随机访问效率。遍历使用get获取元素。
LinkedList 基于链表的线性表,在插入、删除元素时具有较好效率。遍历时使用Iterator。
13.Map
13.1 HashMap Hashtable
Hashtable与Vector一样都是过时的玩意,同步也没卵用,用 Collections.synchronizedMap() 就能够使HashMap具备同步效果。
class A { int count; public A(int count) { this.count = count; } // 根据count的值来判断两个对象是否相等。 public boolean equals(Object obj) { if (obj == this) return true; if (obj != null && obj.getClass() == A.class) { A a = (A)obj; return this.count == a.count; } return false; } // 根据count来计算hashCode值。 public int hashCode() { return this.count; } } class B { // 重写equals()方法,B对象与任何对象通过equals()方法比较都返回true public boolean equals(Object obj) { return true; } } public class HashtableTest { public static void main(String[] args) { Hashtable ht = new Hashtable(); ht.put(new A(60000) , "疯狂Java讲义"); ht.put(new A(87563) , "轻量级Java EE企业应用实战"); ht.put(new A(1232) , new B()); System.out.println(ht); // 只要两个对象通过equals比较返回true, // Hashtable就认为它们是相等的value。 // 由于Hashtable中有一个B对象, // 它与任何对象通过equals比较都相等,所以下面输出true。 System.out.println(ht.containsValue("测试字符串")); // ① 输出true // 只要两个A对象的count相等,它们通过equals比较返回true,且hashCode相等 // Hashtable即认为它们是相同的key,所以下面输出true。 System.out.println(ht.containsKey(new A(87563))); // ② 输出true // 下面语句可以删除最后一个key-value对 ht.remove(new A(1232)); //③ System.out.println(ht); } }
// 1.当用于equals判断的值被修改时,该元素就无法被操作 public class HashMapErrorTest { public static void main(String[] args) { HashMap ht = new HashMap(); // 此处的A类与前一个程序的A类是同一个类 ht.put(new A(60000) , "疯狂Java讲义"); ht.put(new A(87563) , "轻量级Java EE企业应用实战"); System.out.println("--------------1:" + ht); // 获得Hashtable的key Set集合对应的Iterator迭代器 Iterator it = ht.keySet().iterator(); // 取出Map中第一个key,并修改它的count值 A first = (A)it.next(); first.count = 87563; // ① // 输出{A@1560b=疯狂Java讲义, A@1560b=轻量级Java EE企业应用实战} System.out.println("--------------2:" + ht); // 只能删除没有被修改过的key所对应的key-value对 ht.remove(new A(87563)); System.out.println("--------------3:" + ht); // 无法获取剩下的value,下面两行代码都将输出null。 System.out.println(ht.get(new A(87563))); // ② 输出null System.out.println(ht.get(new A(60000))); // ③ 输出null } } //--------------1:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@ea60=疯狂Java讲义, com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=轻量级Java EE企业应用实战} //--------------2:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=疯狂Java讲义, com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=轻量级Java EE企业应用实战} //--------------3:{com.lee.test.java.ebook.crazy_java.u_8_container.c_8_6_map.A@1560b=疯狂Java讲义} //null //null
13.2 LinkedHashMap
13.2.1 LinkedHashMap 是 HashMap的子类,如同LinkedHashSet是HashSet的子类一样,用双向链表维护key-value的顺序,使得迭代的顺序与插入的顺序是一致的。
13.2.2 LinkedHashMap 不用像HashMap一样靠hash控制key-value顺序,同时有避免TreeMap增加的成本,因为要维护插入顺序,故插入速度低于HashMap,但迭代速度要优于HashMap
public class LinkedHashMapTest { public static void main(String[] args) { LinkedHashMap scores = new LinkedHashMap(); scores.put("语文" , 80); scores.put("英文" , 82); scores.put("数学" , 76); // 调用forEach方法遍历scores里的所有key-value对 scores.forEach((key, value) -> System.out.println(key + "-->" + value)); } }
14. Properties
Properties是Hashtable的子类
public class PropertiesTest { public static void main(String[] args) throws Exception { Properties props = new Properties(); // 向Properties中增加属性 props.setProperty("username" , "yeeku"); props.setProperty("password" , "123456"); // 将Properties中的key-value对保存到a.ini文件中 props.store(new FileOutputStream("a.ini") , "comment line"); //① // 新建一个Properties对象 Properties props2 = new Properties(); // 向Properties中增加属性 props2.setProperty("gender" , "male"); // 将a.ini文件中的key-value对追加到props2中 props2.load(new FileInputStream("a.ini") ); //② System.out.println(props2); } }
15.SortedMap
SortedMap是Map的子类接口,TreeMap是接口SortedMap的实现类,与TreeSet的SortedSet关系一样,红黑树结构控制存储。
1.定制排序,传入Comparator的实现类实现compare(a,b)的方法
2.自然排序,让TreeMap中的key元素对象实现Comparable的compareTo(O o)方法
class R implements Comparable { int count; public R(int count) { this.count = count; } public String toString() { return "R[count:" + count + "]"; } // 根据count来判断两个对象是否相等。 public boolean equals(Object obj) { if (this == obj) return true; if (obj != null && obj.getClass() == R.class) { R r = (R)obj; return r.count == this.count; } return false; } // 根据count属性值来判断两个对象的大小。 public int compareTo(Object obj) { R r = (R)obj; return count > r.count ? 1 : count < r.count ? -1 : 0; } } // 1.定制排序,传入Comparator的实现类实现compare(a,b)的方法 // 2.自然排序,让TreeMap中的key元素对象实现Comparable的compareTo(O o)方法 public class TreeMapTest { public static void main(String[] args) { TreeMap tm = new TreeMap((a, b) -> (int)b - (int)a); tm.put(new R(3) , "轻量级Java EE企业应用实战"); tm.put(new R(-5) , "疯狂Java讲义"); tm.put(new R(9) , "疯狂Android讲义"); System.out.println(tm); // 返回该TreeMap的第一个Entry对象 System.out.println(tm.firstEntry()); // 返回该TreeMap的最后一个key值 System.out.println(tm.lastKey()); // 返回该TreeMap的比new R(2)大的最小key值。 System.out.println(tm.higherKey(new R(2))); // 返回该TreeMap的比new R(2)小的最大的key-value对。 System.out.println(tm.lowerEntry(new R(2))); // 返回该TreeMap的子TreeMap System.out.println(tm.subMap(new R(-1) , new R(4))); } }
16.WeakHashMap
与HsahMap的区别在于,HashMap里边对key的存储是强引用,而WeakHashMap是弱引用。即进行GC后,WeakHashMap里边的key因为不是强引用,而有可能会回收。缓冲区的除外。
// 1.new String()只保留了弱引用,而""是字符串缓冲区的,不会被GC。 public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap whm = new WeakHashMap(); // 将WeakHashMap中添加三个key-value对, // 三个key都是匿名字符串对象(没有其他引用) whm.put(new String("语文") , new String("良好")); whm.put(new String("数学") , new String("及格")); whm.put(new String("英文") , new String("中等")); //将 WeakHashMap中添加一个key-value对, // 该key是一个系统缓存的字符串对象。 whm.put("java" , new String("中等")); // ① // 输出whm对象,将看到4个key-value对。 System.out.println(whm); // 通知系统立即进行垃圾回收 System.gc(); System.runFinalization(); // 通常情况下,将只看到一个key-value对。 System.out.println(whm); } } //{英文=中等, java=中等, 数学=及格, 语文=良好} //{java=中等}
17.IdentityHashMap
IdentityHashMap 判断相等需要key1 == key2 严格相等才可以,而HashMap只需要key1和key2通过equals比较相等且hashcode相等。
public class IdentityHashMapTest { public static void main(String[] args) { IdentityHashMap ihm = new IdentityHashMap(); // 下面两行代码将会向IdentityHashMap对象中添加两个key-value对 ihm.put(new String("语文") , 89); ihm.put(new String("语文") , 78); // 下面两行代码只会向IdentityHashMap对象中添加一个key-value对 ihm.put("java" , 93); ihm.put("java" , 98); System.out.println(ihm); } } //{语文=78, java=98, 语文=89}
18.EnumMap
Enum内部以数组实现,所以非常高效
enum Season { SPRING,SUMMER,FALL,WINTER } public class EnumMapTest { public static void main(String[] args) { // 创建EnumMap对象,该EnumMap的所有key都是Season枚举类的枚举值 EnumMap enumMap = new EnumMap(Season.class); enumMap.put(Season.SUMMER , "夏日炎炎"); enumMap.put(Season.SPRING , "春暖花开"); System.out.println(enumMap); } }
桶概念:
HashMap和HashSet通过hash算法存储key元素,而这个key有可能会有重复的情况,所以用了一个集合桶去装这些重复的hash值的元素。相同的桶里边的元素之间是通过链表实现的,必须按顺序存储,故桶内的查找效率就会低了。