Java集合(简单介绍)

集合

1.集合的作用

		在java中我们可以使用数组来保存多个对象,但是数组的长度不可变。如果需要保存数量变化的数据,数据就不太合适了。为了保存数量不确定的数据,以及保存具有映射关系的数据(也被称为关联数组),Java 提供了集合类。**集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类**

2.集合类的分类

​ java集合类型分为Collection和Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类.

下图为collection接口基本结构

Collection接口结构

下图为Map接口基本结构

Map接口结构

Collection

Collection方法分类

1.修改操作

方法名 作用
add() 添加单个数据,结果返回布尔值
remove() 删除单个数据,结果返回布尔值

2.查询操作

方法名 作用
size() 返回此集合中的元素数。
isEmpty() 如果集合中不包含元素,则返回 true 。
contains() 如果此集合包含指定的元素,则返回true。
iterator() 以正确的顺序返回该列表中的元素的迭代器。
toArray() 正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
toArray(T[]) 正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。 如果列表适合指定的数组,则返回其中。 否则,将为指定数组的运行时类型和此列表的大小分配一个新数组。

3.批量操作

方法名 作用
containsAll(Collection<?>) 如果此集合包含指定 集合中的所有元素,则返回true。
addALl(Collection<? extends E>) 批量添加
removeALL(Collection<?>) 批量删除
removeIF(Predicate<? super E>) 条件删除
retainAll(Collection<?>) 保留删除
clear() 清空集合
stream() 返回一个顺序Stream与此集合作为其来源。
parallelStream() 返回可能并行的Stream与此集合作为其来源。 该方法允许返回顺序流。

首先看一下添加操作与批量添加操作

定义一个Fruit类,一个Apple类,以及一个Banana类

public class Fruit {
    private String name;

    public Fruit(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return name;
    }
}
public class Apple extends Fruit{
    public Apple(String name) {
        super(name);
    }
}
public class Banana extends Fruit{
    public Banana(String name) {
        super(name);
    }
}

然后在主方法中写一个集合,并向这个集合中国添加数据

public class Demo01 {
    //首先看一下添加操作boolean add(),添加成功返回True,失败返回False
    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList<>();
        System.out.println(fruits.add(new Apple("红富士苹果")));
        System.out.println(fruits.add(new Apple("青苹果")));
        System.out.println(fruits.add(new Fruit("蛇果")));
        for (Fruit fruit : fruits) {
            System.out.println(fruit);
        }
    }
}

输出:

true
true
true
红富士苹果
青苹果
蛇果 

List fruits = new ArrayList<>();

因为集合中定义的是Fruit,说明该集合只能存储Fruit对象或者Fruit的子类对象

再看一下addall()方法,添加成功返回true,否则返回false

首先定义两个集合,分别为苹果集合和香蕉集合,并向集合中添加数据

public class Demo01 {
    //首先看一下添加操作boolean add(),添加成功返回True,失败返回False
    public static void main(String[] args) {
        List<Apple> apples = new ArrayList<>();
            apples.add(new Apple("红富士"));
            apples.add(new Apple("青苹果"));
            apples.add(new Apple("蛇果"));
        List<Banana> bananas = new ArrayList<>();
        bananas.add(new Banana("帝皇蕉"));
        apples.add(new Apple("海南香蕉"));
        List<Fruit> fruits = new ArrayList<>();
        System.out.println(fruits.addAll(apples));
        System.out.println(fruits.addAll(bananas));
        for (Fruit fruit : fruits) {
            System.out.println(fruit);
        }

    }
    }

集合删除数据

remove()删除单个数据,删除批量数据removeAll,删除符合添加条件的数据,removeIF,删除所有数据clear,即清空数据!

首先先看单个删除操作如何操作的

public class Demo02 {
    public static void main(String[] args) {
        //定义一个数字集合
        List<Integer> numbers = new ArrayList<>();
                numbers.add(1);
                numbers.add(2);
                numbers.add(3);
                numbers.add(4);
                numbers.add(5);
        for (Integer number : numbers) {
            System.out.print(number+" ");
        }
        System.out.println();
        System.out.println("====分===割===线=====");
              numbers.remove(2);
              numbers.remove(3);
        for (Integer number : numbers) {
            System.out.print(number+" ");
        }
    }
}

输出:

1 2 3 4 5 
====分===割===线=====
1 2 4 

可以看到,删除我们打印输出的是1,2,4,可以看到他是先删除的下标为2的数字,然后,后面的数字往前进一个,集合中现在的长度为4,我们再取下标3的数,也就是最后一个数5,打印剩下的数就是1.2.4.

1.removeAll()方法

删除要删除数据中的集合,只要有符合的就执行删除操作

代码示例:

public class Demo03 {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        List<Integer> num=new ArrayList<>();
        num.add(2);
        num.add(3);
        num.add(5);
        num.add(6);
        numbers.removeAll(num);
        for (Integer number : numbers) {
            System.out.print(number+" ");
        }
    }

}

输出:

1  4

2.retainAll()方法,指定要保留的数据集合

public class Demo04 {
    public static void main(String[] args) {

        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        List<Integer> nums = new ArrayList<>();
        nums.add(2);
        nums.add(4);
        nums.add(6);
        numbers.retainAll(nums);
        System.out.println(numbers);
    }
}

输出:

[2, 4]

可以看到,我们把要保留的数放在第二个集合中,当在需要操作的集合中能找到相应的数据,就将其保留!

3.removeIf()方法

public class Demo05 {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        //指定规则删除集合中的数据
        //Predicate接口主要用来判断一个参数是否符合要求
         boolean result=numbers.removeIf(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                //删除所有偶数
                return integer%2==0;
            }
        });
         //看是否删除成功
        System.out.println(result);
        //遍历集合
        for (Integer number : numbers) {
            System.out.print(number+" ");
        }
    }

}

输出:

true
1 3 5 

4.clear()方法,清空集合

public class Demo06 {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        System.out.println(numbers);
        numbers.clear();
        System.out.println(numbers);
    }
}

输出:

[1, 2, 3, 4, 5]
[]

一些常见的其他方法

public class Demo07 {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);
        //集合的元素数
        System.out.println(numbers.size());
        //集合是否为空
        System.out.println(numbers.isEmpty());
        //集合中是否有元素2
        System.out.println(numbers.contains(2));
    }
}

输出:

5
false
true

更多方法,具体的可以查看一下jdk的帮助文档

ArrayList

​ ArrayLisy不但拥有Collection中的方法,还拥有List中的所有方法

特点:

  1. 有序
  2. 可重复
  3. 数据可为null

优点:查询快

缺点:增删慢

1.ArrayList中的构造方法

​ ArrayList中有三种构造方法

  • public ArrayList() 构造一个初始容量为十的空列表。

  • public ArrayList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。

  • public ArrayList(int initialCapacity) 构造具有指定初始容量的空列表。

2.ArrayList中的常用方法

方法 作用
add(E) 添加元素
set(int index,E element) 覆盖指定位置的元素
remove(int index) 删除指定位置的元素
get(int index) 获取指定位置的元素
indexOf(Object o) 获取指定位置的索引
iterator() 获取迭代器
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合
stream() 为集合创建流

LinkedList

​ 拥有Collection里面的所有方法,List中的所有方法,Queue中的所有方法,Deque中的所有方法

1.LinkedList中的构造方法

  • LinkedList() 构造一个空列表。

  • LinkedList(Collection<? extends E> c) 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。

特点:

  1. 有序
  2. 可重复
  3. 可为null

优点:增删块

缺点:查询慢

2.LinkedList的常用方法:

方法 作用
getFirst 返回此列表中的第一个元素。
getLast 返回此列表中的最后一个元素。
removeFirst 从此列表中删除并返回第一个元素。
removeLast 从此列表中删除并返回最后一个元素。
add 将指定的元素追加到此列表的末尾。
addFirst 在该列表开头插入指定的元素。
size 返回此列表中的元素数。
clear 从列表中删除所有元素。 此呼叫返回后,列表将为空。
contains 如果此列表包含指定的元素,则返回true`
listIterator 从列表中的指定位置开始,返回此列表中元素的列表迭代器(按适当的顺序)。
straem 为集合创建流

ArrayList与LinkedList的区别

ArrayLIst LinkedList
数据结构 数组 链表
查询速度
增删速度
内存空间
应用场景 查询较多 增删较多

HashMap

特点:

​ 1.无序

​ 2.key可以为null,哈希值为0

​ 3.key不可以重复,重复的key,新值会覆盖旧值

优点:增删改查快

缺点:无序

1.HashMap的构造方法:

方法 作用
HashMap() 构造一个空的 HashMap ,默认初始容量(16)和默认负载系数(0.75)。
HashMap(int initialCapacity) 构造一个空的 HashMap具有指定的初始容量和默认负载因子(0.75)
HashMap(int initialCapacity, float loadFactor) 构造一个空的HashMap具有指定的初始容量和负载因子。
HashMap(Map<? extends K,? extends V> m) HashMap(int initialCapacity, float loadFactor)构造一个新的 HashMap与指定的相同的映射 Map`

2.HashMap中常用的方法:

方法名 作用
size 返回此地图中键值映射的数量。
isEmpty 如果此地图不包含键值映射,则返回 true 。
get 返回到指定键所映射的值,或null如果此映射包含该键的映射。
put 将指定的值与此映射中的指定键相关联。 如果地图先前包含了该键的映射,则替换旧值。
remove 从该地图中删除指定键的映射(如果存在)。
clear 从这张地图中删除所有的映射。 此呼叫返回后,地图将为空。
containsKey 如果此映射包含指定键的映射,则返回 true 。
keySet 返回此地图中包含的键的Set视图。 该集合由地图支持,因此对地图的更改将反映在集合中,反之亦然。 如果在集合中的迭代正在进行中修改映射(除了通过迭代器自己的remov操作),迭代的结果是未定义的。 该组支持元件移除,即从映射中相应的映射,经由Iterator.remove,Set.remove,removeAll,retainAll和clear操作。 它不支持add或addAll操作。

其中put与get方法在hashmap中用的最为频繁,在实际开发中,hashmap多用于缓存数据

LinkedHashMap

特点:

  1. 有序
  2. key唯一
  3. key为null

优点:有序

LInkedHashMap中常用的方法:

方法 作用
put(K,V) 添加元素
get(Object) 获取指定键的元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键的元素
keyset() 以set集合的形式返回所有值
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合

TreeMap(二叉树映射)

特点:

  1. 对key有序
  2. 无序
  3. key不可为null
  4. key唯一

优点:对key有序

缺点:无序

keymap的常用方法:

方法 作用
put(K,V) 添加元素
get(Object) 获取指定键的元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键的元素
keyset() 以set集合的形式返回所有值
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合
descendingMap 倒序遍历

HashSet(哈希集合)

特点:

  1. 无序
  2. 值唯一
  3. 值可为null

优点:增删改查快

缺点:无序

1.HashSet的构造方法:

构造方法 说明
HashSet() 构造一个新的空集合; 背景HashMap实例具有默认初始容量(16)和负载因子
HashSet(Collection<? extends E> c) 构造一个包含指定集合中的元素的新集合。
HashSet(int initialCapacity) 构造一个新的空集合; 背景HashMap实例具有指定的初始容量和默认负载因子(0.75)
HashSet(int initialCapacity, float loadFactor) 构造一个新的空集合; 背景HashMap实例具有指定的初始容量和指定的负载因子。

2.HashSet的常用方法

方法 作用
add 添加元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键
iteartor 迭代器
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合

3.HashSet与HashMap的区别

Hashmap Hashset
key是key,value是value 把key当成value使用,value再用统一的值填充

LInkedHashSet(链式哈希集合)

特点:

  1. 有序
  2. 值唯一
  3. 值可位null

优点:有序,增删快

缺点:查询慢

1.LinkedHashSet的常用方法

方法 作用
add 添加元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键
iteartor 迭代器
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合

2.LinkedHahsSet与LinkedHashMap的区别

LinkedHashSet LinkedhashMap
存储方式 key是key,value是value 把key当成value使用,value再用统一的值填充
排序方式 添加顺序 访问顺序 添加顺序

TreeSet(二叉树集合)

特点:

  1. 无序
  2. 对值排序
  3. 值不可为null
  4. 值唯一

优点:对值排序

缺点:无序

1.TreeSet的常用方法:

方法 作用
add 添加元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键
iteartor 迭代器
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合
descendingIterator 倒叙遍历

2.HashSet与TreeSet的对比

HashSet LInkEdHashSet Treeset
添加、查询快 添加、修改、删除快;有序 只有需要对元素进行排序时使用

快速失败(fail-fast)机制

​ 一种容器保护机制,防止多个线程并发修改同一个容器的内容,如果发生了并发修改的情况就会触发快速失败机制,也就是抛出ConcurrentModificationException(并发修改异常)

eg:

当你在迭代遍历某个容器的过程中国,另一个线程介入其中,并且插入或删除此容器中的某个元素,那么就会出现问题,单线程和多线程同理!

我们看一下代码:

可以看出,我们在下面迭代遍历的同时,进行插入操作

import java.util.ArrayList;
import java.util.Iterator;

public class FailFast {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Iterator<String> iterator = list.iterator();
        list.add("1");
        list.add("2");
        while (iterator.hasNext()){
            System.out.println(iterator.next());}
    }
    }

输出:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
	at java.util.ArrayList$Itr.next(ArrayList.java:861)
	at com.gather.map.FailFast.main(FailFast.java:14)

那么为了防止这类问题出现,java容器类采用了快速失败机制,主要用与监视容器的变化

那么如何避免上述问题:我们只需要采用线程安全的容器即可

线程不安全 线程安全
ArrayLIst CopyOnWriteArrayList
LinkedList
HashMap ConcurrentHashMap
LinkedHashMap
TreeMap
HashSet CopyOnWriteArraySet
LinkedHashSet
TreeSet

代码示例:

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class FailFast2 {
    public static void main(String[] args) {
        //创建一个支持并发的集合
        CopyOnWriteArrayList list=new CopyOnWriteArrayList();
        //另一个线程修改器
        new Thread(new Runnable() {
            @Override
            public void run() {
                list.add("一个简单的多线程");
                list.add("lingstar");
            }
        }).start();
         //获取迭代器
        Iterator<String> iterator = list.iterator();
        //遍历集合
        while (iterator.hasNext()){
            //获取元素
            System.out.println(iterator.next());
        }
    }
}

输出:

一个简单的多线程
lingstar

ConcurrentHashMap

特点:

  1. 无序
  2. key唯一
  3. key、value不可为null
  4. 线程安全

优点:增删改查快

缺点:无序

1.ConcurrentHashMap的常用方法

方法 作用
put 添加元素
get(Object) 获取指定键的元素
containsKey(Object) 查询集合中是否包含指定键
remove(Object) 删除指定键
keySet() 以set集合的形式返回所有键
size() 获取集合大小
isEmpty() 判断集合是否为空
clear() 清空集合

2.ConcurrentHashMap与HashMap的区别

hashMap ConcurrentHahsmap
线程是否安全 不安全 安全
扩容 单线程扩容 多线程协同扩容
统计元素个数 size baseCount+CounterCell()
key,value能否为null 不能
posted @ 2022-07-20 18:14  星余明  阅读(1553)  评论(0编辑  收藏  举报