Day14——集合

Day14

集合Collection

集合是一种可以存放多个数据的容器

  • List:可重复且有序集(元素是否重复取决于元素的equals()比较的结果)
  • Set:不可重复集

Stream流

采用IO流式想法对集合进行操作,将集合看作一个流进行操作

跳转查看详情

常用方法

向集合中添加元素

使用add方法向集合中添加元素,不需要下标位置来指定存入位置,只需要调用add方法,从首位0开始插入

不需要管理容量,需要多少会自动完成扩容

注:可以存任意数据类型,但基本数据类型无法放入,存放基本数据类型时会自动装箱

方法格式

boolean add();//添加成功返回true,添加失败返回false

示例:

Collection list = new ArrayList();
list.add("one");
list.add("two");
list.add("three");
list.add(1);//自动装箱
System.out.println(list);//打印输出时也不需要用Arrays类转换,直接打印即可
获取集合元素个数

通过size方法返回集合的元素个数

失真现象:If this collection contains more than Integer.MAX_VALUE elements, returns Integer.MAX_VALUE.

size不等价于数组中的length,数组一创建就会固定长度并赋予初始值,所以length一开始就为开始创建的长度

方法格式

int size(Collection collection);
判空

通过isEmpty方法判断集合是否为空,null都没有

方法格式

boolean isEmpty();//无参方法,直接点在集合之后进行判断
清空集合

使用clear方法快速清空集合中所有元素

方法格式

void clear();//无返回值无参方法,直接点在集合后使用
包含

使用contains方法判断集合中是否包含指定元素,包含则返回true

底层判断依据为equals的结果,所以元素重写了equals方法则比较的是元素内部的值,没有重写则比较的是元素对象的地址

方法格式

boolean contains(Object object);

示例:Point没有重写equals方法,所以内部元素相同无法正确判断

HashSet<Object> set = new HashSet<>();
set.add(new Point(1, 2));
set.add(new Point(3, 4));
set.add(new Point(5, 6));

boolean contains = set.contains(new Point(1, 2));
System.out.println("是否包含Point(1, 2): " + contains);//是否包含Point(1, 2): false
并集

使用addAll方法添加集合中所有元素到另一个集合中

注:向set中添加元素时,重复元素无法放入

方法格式

boolean addAll(Collection c);

示例:

Collection languageList = new ArrayList();
languageList.add("java");
languageList.add("c");
languageList.add("c++");
System.out.println("languageList = " + languageList);

ArrayList languageList2 = new ArrayList();
languageList2.add("html");
languageList2.add("css");
languageList.addAll(languageList2);
System.out.println("languageList = " + languageList);

输出

languageList = [java, c, c++]
languageList = [java, c, c++, html, css]
交集

使用retainAll方法将目标集合的内容变为两个集合共有元素的集合

方法格式

boolean retainAll(Collection<?> c);

示例:

Collection languageList = new ArrayList();
languageList.add("java");
languageList.add("c");
languageList.add("c++");
System.out.println("languageList = " + languageList);

Collection languageList3 = new ArrayList();
languageList3.add("java");
languageList3.add("php");
System.out.println("languageList3 = " + languageList3);

languageList.retainAll(languageList3);
System.out.println("languageList = " + languageList);

输出

languageList = [java, c, c++]
languageList3 = [java, php]
languageList = [java]
差集

使用removeAll方法将目标集合变为去除两个集合共有元素的集合

注:区别removeAll与remove的不同

方法格式

boolean removeAll(Collection<?> c);

示例

Collection languageList = new ArrayList();
languageList.add("java");
languageList.add("c");
languageList.add("c++");
System.out.println("languageList = " + languageList);

Collection languageList3 = new ArrayList();
languageList3.add("java");
languageList3.add("php");
System.out.println("languageList3 = " + languageList3);

languageList.removeAll(languageList3);
System.out.println("languageList = " + languageList);

输出

languageList = [java, c, c++]
languageList3 = [java, php]
languageList = [c, c++]

删除指定元素

使用remove方法删除目标集合中的指定元素

注:remove方法用于删除指定元素,若传参时将整个集合传入,则会在目标集合中将参数集合当作一个对象来匹配元素,若目标集合中没有元素为参数集合对象,则目标集合不做修改

方法格式

boolean remove(Object o);

示例:

languageList.remove(languageList3);//将集合作为参数传入,会在languageList中匹配是否有元素是languageList3对象
System.out.println("languageList = " + languageList);//languageList对象的元素中没有languageList3对象,所以不做操作
languageList.remove("java");
System.out.println("languageList = " + languageList);

输出

languageList = [java, c, c++]
languageList = [c, c++]
完全包含

使用containAll方法判断当前集合是否包含给定集合中的所有元素,只要有一个元素不包含,就返回false

方法格式

boolean containsAll(Collection<?> c);

示例:

Collection languageList = new ArrayList();
languageList.add("java");
languageList.add("c");
languageList.add("c++");
System.out.println("languageList = " + languageList);

Collection languageList4 = new ArrayList();
languageList4.add("java");
languageList4.add("c");
System.out.println("languageList4 = " + languageList4);

boolean containsAll = languageList.containsAll(languageList4);
System.out.println("containsAll = " + containsAll);

输出

languageList = [java, c, c++]
languageList4 = [java, c]
containsAll = true

集合元素对象指向问题

[!IMPORTANT]

集合中存放对象时,存放的也是对象的地址,所以对对象进行操作时,集合中的元素会随之改变

如下图,集合c中的对象和p对象本身指向的是同一个Point

示例

Collection<Point> c = new ArrayList<>();
Point p = new Point(1, 2);
c.add(p);
p.setX(2);
System.out.println(p);//Point{x=2, y=2}
System.out.println(c);//[Point{x=2, y=2}]

image-20240323113351501

集合重写toString()方法的格式

集合的toString方法会直接调用各个元素自身的toString方法,若元素自身没有重写该方法,则还是会直接调用Object类中的默认方法,输出地址

[元素1.toString() , 元素2.toString() , ...]

对象存入问题

​ 在Set集合中元素是不允许重复的,但是判断的依据仍然是equals方法的判断结果,所以若存入的对象没有重写equals方法,则默认调用Object类中的方法,比较的是对象的地址,所以即使对象中的内容完全相同,也可以在Set集合中并存

示例:Point没有重写equals方法,可以将重复元素存入set

HashSet<Object> set = new HashSet<>();
set.add(new Point(1, 2));
set.add(new Point(3, 4));
set.add(new Point(5, 6));
set.add(new Point(1, 2));//重复存入,Point没有重写equals方法
System.out.println(set);//[Point{x=1, y=2}, Point{x=3, y=4}, Point{x=5, y=6}, Point{x=1, y=2}]

遍历集合元素

迭代器模式

迭代器规定,迭代器迭代过程中,不可以使用集合的方法进行元素的操作,否则报并发修改异常ConcurrentModificationException

  • 集合提供了统一的遍历元素方式:迭代器模式

  • 集合提供的方法:Iterator iterator()

    java.util.Iterator接口

    该方法会返回一个用于遍历当前集合的迭代器

  • 迭代器接口规定了几个方法,用于遍历集合元素.不同的集合都实现了一个迭代器用于遍历自身元素,我们不需要记住那些实现类的名字。

  • 迭代器遍历集合的遵循的步骤:问->取->删 (删除不是必须操作)

方法格式

boolean hasNext();//校验集合中是否还有下一个元素 -> 问
E next();//从集合中取出下一个元素 -> 取

示例:

// Declare an ArrayList to store strings
ArrayList<String> list = new ArrayList<>();
// Add strings to the ArrayList
list.add("one");
list.add("two");
list.add("three");
list.add("four");

// Create an Iterator object for the ArrayList
Iterator<String> iterator = list.iterator();

// Loop through the ArrayList using the Iterator
while (iterator.hasNext()) {
    // Get the next element from the Iterator
    String element = iterator.next();
    // Print the element
    System.out.println(element);
}
增强for循环

注:集合中使用增强for循环,底层会使用Iterator迭代器实现,所以在增强for循环中也无法使用集合本身的方法

而在数组中使用增强for循环,则会等效为普通for循环

语法结构

for(<?> s : Collection c){
    ...
}

示例:

Collection<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);
for (String s : list) {
    System.out.println(s);
}

List集合

LinkedList和ArrayList

内存中的结构

image-20240323145700629

  • ArrayList底层用顺序表实现,LinkedList底层用链表实现
  • ArrayList查询性能非常高O(1),但插入删除效率差
  • LinkedList在一定阈值内插入删除效率高,查询性能较差

常用方法

获取指定下标位置上的元素

使用get方法获取List中的指定位置元素

示例

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list.get(2));//three
将给定元素存入指定位置

使用set方法将给定的元素存入指定位置,并将原位置的元素返回

方法格式

E set(int index, E element);

示例

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");

System.out.println(list.set(2, "six"));//three

案例——将List中的元素反转

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");

String temp = "";
for (int i = 0; i < list.size() / 2; i++) {
    temp = list.get(i);
    list.set(i, list.get(list.size() - 1 - i));
    list.set(list.size() - 1 - i, temp);
}
System.out.println(list);//[five, four, three, two, one]

插入、移除

List中重写了add和remove方法,用于在指定位置插入给定元素及移除指定位置的元素

方法格式

void add(int index, E element);
E remove(int index);

示例:

  • 使用add方法时,从index指向的位置开始,其后所有元素均向后移,然后再将element插入index位置
  • 使用remove方法时,删除index位置的元素后,从index指向的位置开始,其后所有元素均向前移,并返回删除的元素
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");

list.add(2,"2.5");
System.out.println(list);//[one, two, 2.5, three, four, five]
list.remove(1);
System.out.println(list);//[one, 2.5, three, four, five]
获取List中的子集

List中使用subList方法获取子集

subList方法获取的子集与原List占有相同的存储空间,对子集的操作就是对原集合的操作

方法格式

List<E> subList(int fromIndex, int toIndex);//含左不含右

示例

List<Integer> list = new ArrayList<>();
for (Integer i = 0; i < 10; i++) {
    list.add(i);
}
System.out.println(list);
List<Integer> subbedList = list.subList(3, 7);
System.out.println("list.subList(3,7) = " + subbedList);

//将子集subbedList中所有元素扩大十倍
for (int i = 0; i < subbedList.size(); i++) {
    Integer element = subbedList.get(i);
    element *= 10;
    subbedList.set(i, element);
}
System.out.println("扩大后的list = " + list);//修改子集,原集合随之改变
List转数组

方法结构

规则:若传入数组的长度大于等于List的长度,则直接使用该数组,

​ 长度不足则新建一个数组返回

  1. 参数:自定义的一个数组(含长度)
  2. 返回值:与传入数组同类型的数组
<T> T[] toArray(T[] a)

示例

ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
String[] array = list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(array));//[one, two, three, four, five]
数组转List

调用Arrays类中的asList方法对给定数组进行转换

[!IMPORTANT]

  1. 数组转出的List与原数组的绑定的,修改List就会对原有数组进行修改,反之亦然
  2. 因为数组长度固定,所以不允许对转换出的List进行add操作和remove操作,否则报不支持操作异常UnsupportedOperationException
  3. 若想对集合进行增删操作,需要对原数组进行“扩容”(copyOf)

方法格式

static <T> List<T> asList(T... a)

示例

String[] arrays = {"one","two", "three","four","five"};
List<String> list = Arrays.asList(arrays);
System.out.println("List: "+ list);//List: [one, two, three, four, five]
//对转换出的List进行修改
list.set(2,"3");
System.out.println("Modified List: "+ list);
System.out.println("Array: "+ Arrays.toString(arrays));

//对Array进行修改
arrays[0] = "1";
System.out.println("Modified Array: "+ Arrays.toString(arrays));
System.out.println("List: "+ list);

结果

Modified List: [one, two, 3, four, five]
Array: [one, two, 3, four, five]

Modified Array: [1, two, 3, four, five]
List: [1, two, 3, four, five]
构造器

所有集合都支持一个参数为Collection的构造器,用于在创建集合时将给定集合的所有元素导入

ArrayList<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);//[one, two, three, four, five]

ArrayList<String> list1 = new ArrayList<>(list);
System.out.println(list1);//[one, two, three, four, five]
List排序

集合工具类java.util.Collections提供了一个静态方法sort可以对List集合进行排序

Collections.sort(List list)方法在排序集合时,要求集合元素必须实现一个接口:Comparable

因为该接口中定义了一个用于比较两个对象之间大小关系的方法:compareTo()

sort方法就是利用这个方法确定元素之间大小关系从而进行排序的

方法构造

static <T extends Comparable<? super T>> void sort(List<T> list)

示例

ArrayList<Integer> list = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
    list.add(random.nextInt(100));
}
System.out.println("排序前List:"+list);

Collections.sort(list);
System.out.println("排序后List:"+list);

结果

排序前List[33, 2, 9, 19, 37, 47, 26, 0, 94, 34]
排序后List[0, 2, 9, 19, 26, 33, 34, 37, 47, 94]

自定义比较规则

实际开发中对于集合中元素是自己定义的类时,不建议使用原生sort方法,因为要比较需要自定义类时需要手动让目标类实现Comparable接口,而这样操作会导致程序中出现侵入性

自定义比较规则,若通过实现Comparator接口重写compare方法,自定义比较规则

针对元素为对象的集合,排序时可以使用sort方法的重载方法

方法构造

参数:

  1. list:排序目标List
  2. Comparator c:比较规则,会调用该规则进行比较
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

示例:

ArrayList<Point> list = new ArrayList<>();
list.add(new Point(1, 2));
list.add(new Point(30, 4));
list.add(new Point(15, 6));
list.add(new Point(5, 7));
list.add(new Point(25, 3));
System.out.println(list);
/**
 * 使用Collections.sort(list,Comparator)方法对list进行排序
 * Comparator只需要使用一次,所以使用匿名内部类来实现
 * Comparator接口的compare方法需要返回一个int值,表示排序的顺序
 * 返回正数表示o1在o2之前,返回负数表示o1在o2之后,返回0表示相等
 * 这里按照距离原点的距离进行排序
 * 这里使用匿名内部类来实现Comparator接口,也可以使用Lambda表达式
 * 注意:Lambda表达式只能使用一次,所以这里使用匿名内部类
 * 匿名内部类可以省略参数类型,如果只有一个参数,还可以省略()
 * 匿名内部类可以省略{},如果{}中的代码只有一句,还可以省略{}和return
 */
Comparator<Point> MyComparator = new Comparator<Point>(){
    @Override
    public int compare(Point o1, Point o2) {
        int len1 = o1.getX()*o1.getX() + o1.getY()* o1.getY();
        int len2 = o2.getX()*o2.getX() + o2.getY()* o2.getY();
        if (len1 == len2){
            return 0;
        }
        return len1 > len2 ? 1 : -1;
    }
};
Collections.sort(list, MyComparator);
System.out.println(list);
  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值