[笔记] 疯狂JAVA讲义(第3版)第8章 Java集合
  TEZNKK3IfmPf 2023年11月15日 17 0

第8章 Java集合

Java集合类是一种特别有用的工具类,用于存储数量不等的对象,并可以实现常用的数据结构。

8.1 Java集合概述

在编程时,常常需要集中存放多个数据,使用数组可以存放多个对象,但数组的长度不可变。而且数组无法报错具有映射关系的数据,比如成绩表:语文-80。

为了保存数量不确定,以及具有映射关系的数据,Java提供了集合类。集合类主要保存、盛装其他数据,因此也称为容器类。

集合类和数组不同,数组元素可以是基本类型,也可以是对象。

。集合里只能保存对象(实际保存的是对象的引用变量)。

Java集合类主要由两个接口派生而出:Collection和Map。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bESKdnq-1588248416657)(media/image1.png)]{width=“7.074179790026247in” height=“4.385655074365705in”}

8.2 Collection接口和Iterator接口

Collection接口是List、Set和Queue接口的父接口,该接口里定义的方法可用于操作List、Set和Queue。

Collection定义的方法:

小结:

添加: add,addAll,

清除 clear,

包含元素: contains, containsAll

是否为空:isEmpty

返回Iterator: iterator

删除:remove, removeAll, retainAll(Collection c)//从集合中删除集合c不包含的元素

返回元素个数:size

转换数组:toArray()

//Collection测试

package ch8;

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

public class CollectionTest {

public static void main(String[] args) {

Collection c = new ArrayList();

c.add(“孙悟空”);

c.add(6);

System.out.println(“元素个数”+c.size());

c.remove(6);

System.out.println(“元素个数”+c.size());

System.out.println(“c集合包含字符串(孙悟空)?”+c.contains(“孙悟空”));

c.add(“javaEE”);

System.out.println(“c集合中的元素”+c);

Collection books = new HashSet();

books.add(“JavaEE”);

books.add(“疯狂java”);

System.out.println(“c集合完全包含books集合?”+c.containsAll(books));

c.removeAll(books);

System.out.println(“c集合元素:”+c);

c.clear();

System.out.println(“c集合元素:”+c);

books.retainAll©;

System.out.println(“books集合元素:”+books);

}

}

8.2.1 使用Lambda表达式

Java8为 Iteratable接口新增了一个forEach(Consumer Action)默认方法,参数为一个函数式接口。

而Iteratable接口是Collection接口的父接口,因此Collection集合也可以用调用此方法。

调用forEach方法时,程序会依次将集合元素传给Consumer的accept(T t)方法。

可以使用Lambda表达式来实现。:

package ch8;

import java.util.Collection;

import java.util.HashSet;

public class CollectionEach {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(“javaEE”);

books.add(“疯狂java”);

books.add(“疯狂Android”);

books.forEach(obj->System.out.println(“迭代元素”+obj)); //使用forEach

}

}

8.2.2 使用Java 8 增强的Iterator遍历集合元素

Iterator接口主要用来遍历(迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器。

Iterator定义的4个方法:

Boolean hasNext(); //还没遍历完

Object next(); //返回下一个元素

void remove(); //删除上一次next方法返回的元素

void forEachRemaining(Consumer action); //Java8新增的默认方法,该方法可用Lambda表达式遍历集合元素。

package ch8;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

public class IteratorTest {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(“javaEE”);

books.add(“疯狂java”);

books.add(“疯狂Android”);

books.forEach(obj->System.out.println(“迭代元素”+obj));

Iterator it = books.iterator();

while(it.hasNext()) {

String book = (String)it.next();

System.out.println(book);

if(“疯狂java”.equals(book)) {

it.remove();

}

book = “测试字符串”;//对book赋值,不会改变元素本身

}

System.out.println(books);

}

}

对迭代变量book进行赋值,并没有改变集合元素:iterator并没有把元素本身传递给迭代变量,而是传递值。

使用Iterator迭代访问Collection集合元素时,Collection集合里的元素不能被改变,只能通过Iterator的remove()方法删除上一次next()返回的集合元素。

8.2.3 使用Lambda表达式遍历Iterator

package ch8;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

public class IteratorEachTest {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(“javaEE”);

books.add(“疯狂java”);

books.add(“疯狂Android”);

Iterator it = books.iterator();

it.forEachRemaining(obj->System.out.println(“迭代元素”+obj));

}

}

8.2.4 使用foreach循环遍历集合元素

使用foreach循环访问集合元素:

package ch8;

import java.util.Collection;

import java.util.HashSet;

public class ForeachTest {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(“javaEE”);

books.add(“疯狂java”);

books.add(“疯狂Android”);

for(Object obj : books) {

String book = (String)obj;

System.out.println(book);

//这里不能修改集合:books.remove(book);该语句会引起异常

}

}

}

8.2.5 使用Java8 新增的Predicate操作集合

Java8为Collection集合新增了一个removeIf(Predicate filter)方法,该方法会批量删除符合filter条件的元素。

Pridicate 也是函数式接口,可以用Lambda表达式来代替。

package ch8;

import java.util.Collection;

import java.util.HashSet;

public class PredicateTest {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(new String(“轻量级jave EE企业应用实战”));

books.add(new String(“疯狂Java讲义”));

books.add(new String(“疯狂IOS讲义”));

books.removeIf(ele->((String)ele).length()<10); //使用removeIf

System.out.println(books);

}

}

使用Predicate可以简化集合的运算,假设有3个统计需求:1、统计出现疯狂的图书数量;2、统计包含Java的图书数量;3、统计名字长度大于10的图书数量

使用Predicate只需要一个方法:

package ch8;

import java.util.Collection;

import java.util.HashSet;

import java.util.function.Predicate;

public class PredicateTest2 {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(new String(“轻量级jave EE企业应用实战”));

books.add(new String(“疯狂Java讲义”));

books.add(new String(“疯狂IOS讲义”));

System.out.println(calAll(books, ele->((String)ele).contains(“疯狂”)));

System.out.println(calAll(books, ele->((String)ele).contains(“Java”)));

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) {

if(p.test(obj)) { //调用Predicate的test方法,判断对象是否满足条件p。

total++;

}

}

return total;

}

}

8.2.6 使用Java8新增的Stream操作集合

Java8 新增了Stream、IntStream、LongStream、DoubleStream等流式API,代表多个支持串型和并行聚集操作的元素。

Stream是通用的流接口,而剩下3个则是对应元素的流。

Java8 还为流式API提供了对应的Builder,如Stream.Builder,可以通过调用Builder来创建对应的流。

创建Stream的步骤:

1、使用Stream类的builder()类方法,创建Builder。

2、重复调用Builder的add()方法向流中添加元素

3、调用Builder的build()方法获取对应的流

4、调用Stream的聚集方法。

//对于大部分聚集办法而言,每个Stream只能执行一次聚集方法。

package ch8;

import java.util.stream.IntStream;

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.max().getAsInt());

//System.out.println("最小值: "+is.min().getAsInt());

//System.out.println(“总和:”+is.sum());

//System.out.println(“元素数”+is.count());

//System.out.println(“平均值”+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。

IntStream newIs = is.map(ele->ele*2+1);

newIs.forEach(System.out::println);

}

}

聚集方法可以是中间的,也可以是末端的。

中间方法:允许流保持打开,并调用后续方法。如上述的map()方法。中间方法返回值是另一个流。

末端方法:对流的最终操作,将流结束,使流不可再用。 如上述的sum(),count()方法。

常用中间方法小结:

过滤,映射,逐个操作测试,排序所有重复元素,排序,限制最大访问元素个数。

常用末端方法:

遍历执行,转换数组,合并,最大/小值,数量,Match,返回元素

Java8运行使用流式API操作集合。Collection接口提供一个stream()默认方法,返回对应的流。

package ch8;

import java.util.Collection;

import java.util.HashSet;

public class CollectionStream {

public static void main(String[] args) {

Collection books = new HashSet();

books.add(new String(“轻量级jave EE企业应用实战”));

books.add(new String(“疯狂Java讲义”));

books.add(new String(“疯狂IOS讲义”));

System.out.println(books.stream().filter(ele->((String)ele).contains(“疯狂”)).count());

System.out.println(books.stream().filter(ele->((String)ele).contains(“Java”)).count());

System.out.println(books.stream().filter(ele->((String)ele).length()>10).count());

books.stream().mapToInt(ele->((String)ele).length()).forEach(System.out::println);

}

}

8.3 Set集合

Set集合类似于一个罐子,可以把对象丢进Set集合中,而Set不会记住元素的顺序。

Set集合和Collection基本相似。只是Set集合不允许包含重复元素。

8.3.1 HashSet类

HashSet是Set类接口的典型实现,大多数使用Set集合时就是使用这个实现类。

HashSet按Hash算法存储集合中的元素,具有很好的存取和查找性能。

HashSet具有如下特点:

1、不保证元素的排列顺序

2、不是同步的。多个线程访问一个HashSet时,需要程序员保证其同步。

3、集合元素值可以是null。

HashSet集合判断元素相等的标准是 两个对象equals()相等,且hashCode()相等。

@如果需要将某个类的对象保存到HashSet中,重写equals()方法和hashCode()方法时,尽量保证两个对象通过equals()返回true时,hashCode()返回值也相等。

HashSet中每个能存储元素的"槽位"(slot)通常被称为"桶"(bucket),如果多个元素hashCode相等,而equals返回false,就需要在一个桶中放多个元素,会导致性能下降。

@重写hashCode()的原则:同一个对象hashCode()返回值始终相等; 两个对象equals()返回true时,hashCode()返回相等的值。

对象中equals()方法用来比较的实例变量,应该用于计算hashCode值。

重写hashCode()的一般步骤:

1、把对象内每个有意义的实例变量都计算出一个int类型的hashCode值。计算方法见表8.1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QHd8pjVb-1588248416665)(media/image2.png)]{width=“8.300698818897638in” height=“1.710492125984252in”}

2、用第1步计算出的多个hashCode组合计算出一个hashCode返回:

return f1.hashCode()*19 +(int) f2 *31 //19,31是质数,用来避免直接相加偶然相等。

如果向HashSet添加一个可变对象后,后面程序修改了该可变对象的实例变量,则可能导致它与集合中其它元素相同。

这就可能导致HashSet中包含两个相同的对象。这会导致该集合行为混乱。

8.3.2 LinkedHashSet类

HashSet子类。它会使用链表维护元素的次序,使得元素看起来是以插入顺序保存的。

输出LinkedHashSet集合的元素时,元素的顺序总是和添加顺序一致。

8.3.3 TreeSet类

TreeSet类是Sorted接口的实现类。可以确保元素处于排序状态(默认升序)。

TreeSet类的额外方法:

访问第一个、最后一个、前一个、后一个。以及3个获取子集的方法。

package ch8;

import java.util.TreeSet;

public class TreeSetTest {

public static void main(String[] args) {

TreeSet nums = new TreeSet();

nums.add(5);

nums.add(2);

nums.add(1);

nums.add(4);

System.out.println(nums); //输出1,2,4,5

System.out.println(nums.first());

System.out.println(nums.last());

System.out.println(nums.headSet(4));//小于4的子集,不含4

System.out.println(nums.tailSet(4));//大于等于4的子集,含4

System.out.println(nums.subSet(2, 4));//大于等于2,小于4

}

}

TreeSet默认采用自然排序(升序排序)。调用元素的compareTo(Object obj)方法比较大小,然后升序排序。

TreeSet内的对象必须实现Compareable接口,(实现compareTo()方法)。

TreeSet内的对象应该是一个类的对象,否则无法调用compareTo()方法。//大部分compareTo()方法都要进行强制类型转换。即使用户自定义类实现Compareable接口,compareTo()不使用强制类型转换,但取出元素时,仍然会发生ClassCastException。总之, TreeSet里只能添加一种类型的对象。

@compareTo()和equals()方法:compareTo()返回0时,equals()应该返回true;

@ 与HashSet类似,建议不要修改放入TreeSet集合中元素的关键实例变量。

2.定制顺序

如果需要定制顺序,则需要在创建TreeSet集合对象时,提供一个Comparator对象与该集合关联。Comparator对象负责对集合元素排序。

Comparator接口包含一个int compare(T o1,T o2)方法。返回正整数则o1大于o2,返回0,相等,返回负数,o1小于o2.

package ch8;

import java.util.TreeSet;

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) {

TreeSet ts = new TreeSet( (o1,o2)->{ //Comparator ,使用Lambda表达式简写。

M m1 = (M)o1;

M m2 = (M)o2;


m1.age<m2.age?1 :0;

});

ts.add(new M(5));

ts.add(new M(9));

ts.add(new M(3));

System.out.println(ts);

}

}

8.3.4 EnumSet类

专门为枚举可设计的集合类。

元素必须是指定枚举类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KORJELFO-1588248416667)(media/image3.png)]{width=“8.586475284339457in” height=“3.3018438320209973in”}

package ch8;

import java.util.EnumSet;

enum Season{

SPRING,SUMMER,FAIL,WINTERL

}

public class EnumSetTest {

public static void main(String[] args) {

EnumSet es1 = EnumSet.allOf(Season.class);

System.out.println(es1);

EnumSet es2 = EnumSet.noneOf(Season.class);

System.out.println(es2);

es2.add(Season.WINTERL);

System.out.println(es2);

EnumSet es3 = EnumSet.of(Season.FAIL,Season.WINTERL);

System.out.println(es3);

EnumSet es4 = EnumSet.range(Season.SUMMER, Season.WINTERL);

System.out.println(es4);

EnumSet es5 = EnumSet.complementOf(es4);

System.out.println(es5);

}

}

//可以使用EnumSet.copyOf© 复制一个Collection集合中的元素,前提是c中元素必须是同一个枚举类的枚举值。

8.3.5各Set实现类的性能分析

HashSet性能好

TreeSet 可以排序。

LinkedHashSet 遍历快。

EnumSet专为枚举设计。

8.4 List集合

List集合代表代表一个元素有序、可重复的集合。

List默认按索引的添加顺序设置元素索引(从0开始)。

8.4.1 Java8改进的List接口和ListIterator接口

List中增加了根据索引操作集合的方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iqts9foy-1588248416669)(media/image4.png)]{width=“7.973155074365704in” height=“3.7639337270341207in”}

package ch8;

import java.util.ArrayList;

import java.util.List;

public class ListTest {

public static void main(String[] args) {

List books = new ArrayList();

books.add(new String(“轻量级jave EE企业应用实战”));

books.add(new String(“疯狂Java讲义”));

books.add(new String(“疯狂IOS讲义”));

System.out.println(books);

books.add(1,new String(“疯狂Ajax讲义”));

for(int i = 0 ; i < books.size() ; i++ ) {

System.out.println(books.get(i));

}

books.remove(2);

System.out.println(books);

System.out.println(books.indexOf(new String(“疯狂Ajax讲义”)));

books.set(1, new String(“疯狂java讲义”));

System.out.println(books);

System.out.println(books.subList(1, 2));

}

}

List 判断对象相等的标准是equals()方法返回true。

//sort和replace方法

package ch8;

import java.util.ArrayList;

import java.util.List;

public class ListTest3 {

public static void main(String[] args) {

List books = new ArrayList();

books.add(new String(“轻量级jave EE企业应用实战”));

books.add(new String(“疯狂Java讲义”));

books.add(new String(“疯狂IOS讲义”));

books.add(new String(“疯狂Ajax讲义”));

//sort

books.sort((o1,o2)->((String)o1).length()-((String)o2).length());

System.out.println(books);

//replaceAll

books.replaceAll(ele->((String)ele).length());

System.out.println(books);

}

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ioufkGkk-1588248416673)(media/image5.png)]{width=“7.838729221347331in” height=“1.4366797900262467in”}

ListIterator增加了向前迭代和添加元素。

package ch8;

import java.util.ArrayList;

import java.util.List;

import java.util.ListIterator;

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());

}

}

}

8.4.2 ArrayList和Vector实现类

List的两个实现类。ArrayList和Vector都是基于数组实现的List类,封装了一个动态、可再分配的Object[] 数组。

允许使用initialCapacity参数设置数组长度,当元素超出该长度时,initalCapacity会自动增加。

通常无需关系initalCapacity,但如果要添加大量元素时,可以使用ensureCapacity(int minCapacity)一次性增加(到)initalCapacity。可以减少分配次数,提高性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46jLwn8w-1588248416674)(media/image6.png)]{width=“7.544671916010499in” height=“1.2098359580052493in”}

ArrayList和Vector用法上几乎完全相同,但Vector是一个古老的集合,里面有一些方法名很长的方法。

除此之外,ArrayList是线程不安全的。

Vector还提供一个Stack子类,模拟栈。由于Vector太古老了,不推荐使用Vector类。

8.4.3 固定长度的List

Arrays.asList(Object… a),将一个数组或指个数的对象转换成一个List集合,该集合是Arrays的内部类ArrayList的实例。

Arrays.ArrayList是一个固定长度的List集合,程序只能遍历集合元素,不可增减。

package ch8;

import java.util.Arrays;

import java.util.List;

public class FixedSizeList {

public static void main(String[] args) {

List fixedList = Arrays.asList(“fk java”,“java EE”);

System.out.println(fixedList.getClass());

fixedList.forEach(System.out::println);

}

}

8.5 Queue集合

Queue用于模拟队列。队列是先进先出(FIFO)的容器。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VxVKZt0b-1588248416675)(media/image7.png)]{width=“7.628687664041995in” height=“1.873565179352581in”}

8.5.1 PriorityQueue

Queue的比较标准的实现类。但PriorityQueue保存元素的顺序是按照元素的大小排序的。

因此,并不是按照FIFO原则。

package ch8;

import java.util.PriorityQueue;

public class PriorityQueueTest {

public static void main(String[] args) {

PriorityQueue pq = new PriorityQueue();

pq.offer(6);

pq.offer(-3);

pq.offer(20);

pq.offer(18);

System.out.println(pq); //输出[-3,6,20,18],受到toString()的影响,实际上调用poll()是按从小到大排序的。

System.out.println(pq.poll());

System.out.println(pq.poll());

System.out.println(pq.poll());

System.out.println(pq.poll());

}

}

PriorityQueue的排序方式和TreeSet基本一致。

8.5.2 Deque接口和ArrayDeque实现类

Deque是一个双端序列。允许从两端操作数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uwrZi1Er-1588248416675)(media/image8.png)]{width=“7.922744969378828in” height=“4.923360673665792in”}

Deque接口提供了一个典型的实现类:ArrayDeque,可以用来实现Stack和Queue。

package ch8;

import java.util.ArrayDeque;

public class ArrayDequeueStack {

public static void main(String[] args) {

ArrayDeque stack = new ArrayDeque();

stack.push(“java”);

stack.push(“javase”);

stack.push(“Android”);

System.out.println(stack);

System.out.println(stack.peek());

System.out.println(stack);

System.out.println(stack.pop());

System.out.println(stack);

}

}

package ch8;

import java.util.ArrayDeque;

public class ArrayDequeQueue {

public static void main(String[] args) {

ArrayDeque queue = new ArrayDeque();

queue.offer(“java”);

queue.offer(“javaee”);

queue.offer(“Android”);

System.out.println(queue);

System.out.println(queue.peek());

System.out.println(queue);

System.out.println(queue.poll());

System.out.println(queue);

}

}

8.5.3 LinkedList实现类

List的实现类,此外,LinkedList还实现了Deque接口。

package ch8;

import java.util.LinkedList;

public class LinkedListTest {

public static void main(String[] args) {

LinkedList books = new LinkedList();

books.offer(“java”);

books.push(“javaee”);

books.offerFirst(“Android”);

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());

System.out.println(books);

}

}

8.5.4 各种线性表的性能分析

List:线性表接口

ArrayList、LinkedList 两种实现

Queue:队列

Deque:双端队列

一般来说,ArrayList随机访问性能好,LinkedList插入删除时性能好。总体来说,ArrayList性能更好。

List使用使用建议:

遍历:对于ArrayList,使用随机访问 get()方法来遍历;而LinkedList,使用迭代器(Iterator)遍历

线程安全:多线程时,考虑使用Collection将集合包装成线程安全的集合。

8.6 Java 8 增强的Map集合

Map用于保存具有映射关系的数据,Map集合里保存着两组值,一组保存Key,另一组保存Value。

key和value都可以是任何类型的数据,key不能重复。

key -value一一对应。

@key集存储方式和Set存储形式完全相同。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PWWffom-1588248416677)(media/image9.png)]{width=“9.317416885389326in” height=“6.998565179352581in”}

package ch8;

import java.util.HashMap;

import java.util.Map;

public class MapTest {

public static void main(String[] args) {

Map map = new HashMap();

//放入key-value对,value可以重复,如果放入重复的key,新的value值会覆盖原来的value

map.put(“疯狂Java讲义”,109);

map.put(“疯狂IOS讲义”,10);

System.out.println(map);

//判断是否包含指定key

System.out.println(“包含值 疯狂IOS讲义的key:”+map.containsKey(“疯狂IOS讲义”));

//判断是否包含指定value

System.out.println(“包含值为99的value:”+map.containsValue(10));

//获取key集合,通过遍历key遍历key-value对

for(Object key : map.keySet()) {

System.out.println(key+"–>"+map.get(key));

}

map.remove(“疯狂IOS讲义”);//根据key来删除key-value对

System.out.println(map);

}

}

8.6.1 java8为Map新增的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ngbFHAIz-1588248416679)(media/image10.png)]{width=“8.065573053368329in” height=“7.191802274715661in”}

package ch8;

import java.util.HashMap;

import java.util.Map;

public class MapTest2 {

public static void main(String[] args) {

Map map = new HashMap();

//放入key-value对

map.put(“疯狂java”,109);

map.put(“疯狂IOS”, 99);

map.put(“疯狂Ajex”, 79);

map.replace(“疯狂XML”, 66); //替换key为"疯狂XML"的value。但由于原map没有此key,所以不会替换。也不会新加键值对

System.out.println(map);

//覆盖原value, 变成oldV + 10

map.merge(“疯狂IOS”, 10,

(oldV,param)->(Integer)oldV + (Integer)param);

System.out.println(map);

//当key为java对应的value为null或不存在时,使用计算的结果作为新value

map.computeIfAbsent(“java”, (key)->((String)key).length());

System.out.println(map);

//key对应value存在时,计算新value

map.computeIfPresent(“java”, (key,value)->(Integer)value*(Integer)value);

System.out.println(map);

}

}

8.6.2 java 8改进的HashMap和Hashtable实现类

Hashtable是一个古老的Map实现类,不推荐使用。

为了能够在HashMap中存储对象,作为key的对象必须实现hashCode()和equals()方法。

8.6.3 LinkedMap实现类

使用双向链表维护key的次序。

package ch8;

import java.util.LinkedHashMap;

public class LinkedHashMapTest {

public static void main(String[] args) {

LinkedHashMap scores = new LinkedHashMap();

scores.put(“语文”,90);

scores.put(“数学”,92);

scores.put(“英语”,80);

scores.forEach((key,value)->System.out.println(key+"–>"+value));

}

}

8.6.4 使用Properties读取属性文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qyuatnOx-1588248416681)(media/image11.png)]{width=“8.073975284339458in” height=“4.318442694663167in”}

package ch8;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.util.Properties;

public class PropertiesTest {

public static void main(String[] args)throws Exception {

Properties props = new Properties();

//添加属性

props.setProperty(“username”, “yuke”);

props.setProperty(“password”, “123456”);

//保存至a.ini文件

props.store(new FileOutputStream(“a.ini”),“comment line”);

Properties p2 = new Properties();

p2.setProperty(“gender”, “male”);

//将a.ini中key-value追加到p2中

p2.load(new FileInputStream(“a.ini”));

System.out.println(p2);

}

}

8.6.5 SortedMap接口和TreeMap实现类。

TreeMap存储key-value时,根据key进行排序,保证有序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7B5lp8Qi-1588248416681)(media/image12.png)]{width=“8.157991032370953in” height=“7.8471303587051615in”}

8.6.6 WeakHashMap实现类

类似HashMap,但WeakHashMap只保留对实际对象的弱引用,对象在垃圾回收时可能会被回收。

8.6.7 IdentityHashMap实现类

类似HashMap,但处理相等的key时,仅在key1==key2严格相等时,才认为相等。而HashMap只判断equals()和hashCode()方法。

8.6.8 EnumMap实现类

创建EnumMap时必须指定一个枚举类。

8.6.9 各Map实现类的性能分析

对于一般场景,应该考虑使用HashMap.

如果需要排序,则可以考虑TreeMap。

8.7 HashSet和HashMap的性能选项

HashSet类采用hash算法决定元素存储位置,并通过hash算法来控制集合的大小;

hash表里可以存储元素的位置称为"桶(bucket)",通常情况下,单个"桶"存放一个元素,此时有最好的性能。

hash算法根据hashCode值计算出"桶"的位置,接着从"桶"中取出元素。

但发生hash冲突时,单个桶会存储多个元素,这些元素以链表形式存储,必须按顺序搜索。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7XLY8aPY-1588248416682)(media/image13.png)]{width=“3.1758191163604548in” height=“1.6887292213473315in”}

HashSet、HashMap的hash表中都包含如下属性:

容量(capacity):桶数量

初始化容量(initial capacity):

尺寸(size):当前数量

负载因子(load factor):负载因子等于size/capacity,负载因子=0,代表空,负载因子=0.5,代表半满。

负载极限:0~1,当负载因子达到负载极限时,hash表会自动成倍增加容量。默认值0.75.

8.8 操作集合类的工具类:Collections

Collections类提供对集合元素排序、查询、修改等操作。

8.8.1 排序操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x0VXM5RJ-1588248416683)(media/image14.png)]{width=“7.586679790026246in” height=“2.1424179790026248in”}

package ch8;

import java.util.ArrayList;

import java.util.Collections;

public class SortTest {

public static void main(String[] args) {

ArrayList nums = new ArrayList();

nums.add(2);

nums.add(-5);

nums.add(3);

nums.add(0);

System.out.println(nums);

Collections.reverse(nums);//翻转

System.out.println(nums);

Collections.sort(nums);//排序

System.out.println(nums);

Collections.shuffle(nums);//随机顺序

System.out.println(nums);

}

}

8.8.2 查找、替换操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gs5PfYPQ-1588248416684)(media/image15.png)]{width=“7.947950568678915in” height=“3.94876968503937in”}

package ch8;

import java.util.ArrayList;

import java.util.Collections;

public class SearchTest {

public static void main(String[] args) {

ArrayList nums = new ArrayList();

nums.add(2);

nums.add(-5);

nums.add(3);

nums.add(0);

System.out.println(nums);

System.out.println(Collections.max(nums));

System.out.println(Collections.min(nums));

Collections.replaceAll(nums, 0, 1);//替换

System.out.println(nums);

System.out.println(Collections.frequency(nums, -5));

Collections.sort(nums);//排序

System.out.println(nums);

System.out.println(Collections.binarySearch(nums, 3));//二分查找,要求是排序好的

}

}

8.8.3 同步控制

Collections类提供多个synchronizedXxx()方法,可以将指定集合包装成线程同步的集合。

如:

List list = Collections.synchronizedList(new ArrayList());

8.8.4 设置不可变集合

Collections类提供三类方法来返回一个不可变的集合:

emptyXxx(): 返回一个不可变的Xxx

singletonXxx():返回一个只包含指定对象的xx

unmodifiableXxx():返回指定对象的不可变视图。

package ch8;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Set;

public class UnmodifiableTest {

public static void main(String[] args) {

List unmodifiableList = Collections.emptyList();

Set unmodifiableSet = Collections.singleton(“疯狂Java讲义”);

Map scores = new HashMap();

scores.put(“语文”,100);

scores.put(“数学”,99);

Map unmodifiableMap = Collections.unmodifiableMap(scores);

}

}

8.9 繁琐的接口:Enumeration 很古老,建议略过,当然我只是建议

//小结,Java集合,内容很多,很难记住每个类的细节,看完书后要做一下精简版的总结。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月15日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   19天前   43   0   0 java
  TEZNKK3IfmPf   2024年05月31日   54   0   0 java
TEZNKK3IfmPf