Java集合的使用方法

每次用到什么list, map时都要Google一下初始化,取值各种方法,还有Arrays工具类等等,真的感觉Java很麻烦不习惯,还是写个总结好好梳理一下吧,至于这些类的底层实现以及运行效率分析什么的以后再做总结吧。

另外使用集合而不是数组的主要原因是集合提供了很多方法,并且长度是可变的。首先集合分两大类:

mYmPQU.png

Collection

有各种数据结构,就分了多种集合类,然后这些集合类共性提取,最终形成了一个集合的继承体系,最高层的类就是collection。

collection的功能有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
boolean add(Object obj)    //添加一个元素 
boolean addAll(Collection c) //添加一个集合的元素

void clear() //移除所有元素
boolean remove(Object obj) //移除一个元素
boolean removeAll(Collection c) //移除一个集合的元素

boolean contains(Object obj) //判断集合是否包含该元素
boolean containsAll(Collection c) //判断是否包含参数集合中的所有元素
boolean isEmpty() //是否为空

Iterator<E> Iterator() /迭代器

int size() //元素个数

boolean retainAll(Collection c) //取交集,返回值看A是否有变化

迭代器

Collection接口继承了Iterable接口,他返回一个Iterator,Iterator有三个方法

hasNext, next(), remove() 但没有实现,要在子类中进行实现了

List

元素有序,可重复。ListIterator接口多了几个方法,有三个常用子类

  • ArrayList:数组,线程不安全
  • LinkedList:双向链表,线程不安全
  • Vector:数组,线程安全

list 初始化:

1
2
3
4
5
6
7
8
9
10
11
12
List<String> str = new LinkedList<>();
str.add("word");

List<String> str = new LinkedList<>(){{
add("word");
}} //外层的 {} 定义了一个 LinkedList 的匿名内部类。内层的 {} 的定义了一个实例初始化代码块

List<String> str = Arrays.asList("a", "b", "c");

List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList()); //JDK8

List<String> list = Lists.newArrayList("a", "b", "c"); //JDK9

这里new 后面的LinkedList 换成ArrayList 也是没有任何问题的,都是向上转型。

Arrays是Array的工具类,其静态方法定义了对Array的各种操作

List 遍历方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
List<Object[]> obj = new ArrayList<>();
for(int i=0; i<obj.size(); i++){
Object[] temp = obj.get(i);
}

//使用迭代器
for(Iterator iterator = obj.iterator(); iterator.hasNext();){
Object[] temp = (Object[])iterator.next();
}

for(Object[] temp: obj){
System.out.println(temp);
}

ArrayList 增删改查方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void add(int index, Element e)    //增加指定元素到链表指定位置

E set(int index, E element) //将链表中指定位置上的元素替换成新元素。

boolean contains(Object o) //如果链表包含指定元素,返回true
int indexOf(Object o) //返回元素在链表中第一次出现的位置,如果返回-1,表示链表中没有这个元素
int lastIndexOf(Object o) //返回元素在链表中最后一次出现的位置,如果返回-1,表示链表中没有这个元素

boolean isEmpty() //返回true表示链表中没有任何元素.

int size() //返回链表长度

void removeRange(int start, int end) //删除链表中从某一个位置开始到某一个位置结束的元素
E remove(int index) //删除链表中指定位置的元素

LinkedList 增删改查方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
boolean list.add()
boolean list.addAll(blist);
boolean list.addFirst();
boolean list.addLast();

Object clone() //返回一个集合的拷贝。

boolean contains(Object o) //判断一个集合是否包含某个元素,如果包含则返回true,否则返回false,如果要改写判断是否包含的规则,则需要重写equals方法。
Object get(int index) //根据下标来获取集合元素
Object list.getFirst();
int indexOf(Object o) //通过元素来找到它所在集合的下标。

Object remove(int index) //通过下标来删除指定元素。
Object list.removeFirst()

int size() //返回集合的长度

Object[] toArray() //返回包含集合里面所有元素的数组,用于将集合转成数组。

Arrays 的方法:

和下面的collections一样,方法都是静态的,创建之后

1
2
3
4
5
6
7
Arrays.asList()  //将Array包装成一个List
Arrays.equals(Object[] array1, Object[] array2) 与deepEquals //判断两个数组是否相等(哈希值),如果两个数组包含的对应位置上的元素相等或者两个数组同为null,equals返回true。deepEquals适用于多维数组。
Arrays.fill(Object[] array, Object obj) //用指定元素填充整个数组(会替换掉数组中原来的元素)
Arrays.sort(Object[] array)
Arrays.copyOf(T[] original, int newLength) //拷贝数组,其内部调用了 System.arraycopy() 方法,从下标0开始,如果超过原数组长度,会用null进行填充
Arrays.toString(Object[] array) //返回数组元素的字符串形式
Arrays.binarySearch() //在调用该方法之前,必须先调用sort()方法进行排序,如果数组没有排序, 那么结果是不确定的

Collections 的方法:

1
2
3
4
5
6
7
public static <T> boolean addAll(Collection<? super T> c, T… elements);    //添加
fill(List list, Object obj); //使用指定对象填充

public static void reverse(List<?> list); //直接反转集合的元素
public static <T> void sort(List<T> list, Comparator<? super T> c); //排序
min(Collection coll, Comparator comp); //根据自定义比较器,返回最小元素
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key); //搜索

Queue 和 Stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1.栈(Stack):继承自Vector
Stack<String> s = new Stack<String>();

peek(): //只取出栈顶值,但不会对栈进行操作,如果不断去做操作,最后的得到的值是相同,此值是最后进去的值
push(T): //向栈中添加值
pop(): //出栈,并操作栈,取出后进去的值,并删除,然后移动指针
empty() //判定栈是否为空
search(num) //判端元素num是否在栈中,如果在返回1,不在返回-1


//2.队列(Queue):继承自Collection,LinkedList实现了其接口,但是Queue的对象只能使用LinkedList一部分方法
Queue<Integer> queue = new LinkedList<>();

peek(): //只取出队列中的值,不会进行操作,如果不断去做操作,最后的得到的值是相同,此值是最先进去的值
offer(T): //向队列中添加值
poll(): //出队列,并操作队列,取出先进队列的值,并删除,然后移动指针

Set

元素不可重复,存储无序(存入和取出的顺序不一定相同),三个常用子类:

  • HashSet:哈希表,无序
  • TreeSet:红黑树,有序
  • LinkedHashSet:底层数据结构是哈希表和链表

Set具有与Collection完全一样的接口,因此没有任何额外的功能

Map

类型区别

  • HashMap

    最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null(多条会覆盖);允许多条记录的值为 Null。非同步的。

  • TreeMap

    能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。

  • Hashtable

    与 HashMap类似,不同的是:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。

  • LinkedHashMap

    保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。

常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
Map<String, String> map = new HashMap<String, String>();   //Map 初始化

map.put("key1", "value1"); //插入元素

map.get("key1"); //获取元素
containsKey(Object key); //如果 Map 包含指定键的映射,则返回 true
containsValue(Object value); //如果此 Map 将一个或多个键映射到指定值,则返回 true

map.remove("key1"); //移除元素
map.clear(); //清空map

keySet() //返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)
entrySet() //返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素

遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//========增强for循环========:
//使用keySet()遍历
for (String key : map.keySet()) {
System.out.println(key + " :" + map.get(key));
}

//使用entrySet()遍历
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " :" + entry.getValue());
}

//========迭代器遍历========:
//使用keySet()遍历
Iterator<String> iterator = map.keySet().iterator();
while(iterator.hasNext()){
String key = iterator.next();
System.out.println(key + " : " + map.get(key));
}

//使用entrySet()遍历
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey() + " : " + entry.getValue());
}

速度比较:

  1. 增强for循环使用方便,但性能较差,不适合处理超大量级的数据。
  2. 迭代器的遍历速度要比增强for循环快很多,是增强for循环的2倍左右。
  3. 使用entrySet遍历的速度要比keySet快很多,是keySet的1.5倍左右。

各种排序

List 的排序

数组而言,你可以直接使用Arrays.sort对于List和Vector而言,你可以使用Collections.sort方法。使用Collections工具类进行排序,有两种使用方法:

  1. 通过list的类对象实现comparable接口,需要重写 compareTo() 方法,这个方法接收一个同类型的对象,并实现这个对象和传递给方法的另一个对象比较的逻辑。compareTo()方法返回Int类型的比较结果,正值表示当前对象比传递给 comPareTO()的对象负值表示当前对象比传递给 comPareTO()的对象

    1
    2
    3
    4
    5
    6
    public class Student implements Comparable{
    @Override
    public int compareTo(User arg0) {
    return this.getOrder().compareTo(arg0.getOrder());
    }
    }
  2. 根据Collections.sort重载方法来实现:也提供了一个单一的比较方法叫作 compare()。然而,与 Comparable的 compareTo() 方法不同的是,这个 compare() 接受两个同类型的不同对象进行比较

    1
    2
    3
    4
    5
    Collections.sort(list,new Comparator<User>(){
    public int compare(User arg0, User arg1) {
    return arg0.getPrice().compareTo(arg1.getPrice());
    }
    });

Map 排序

  1. HashMap、Hashtable、LinkedHashMap排序:通过ArrayList构造函数把map.entrySet()转换成list

    1
    2
    3
    4
    5
    6
    7
    8
    Map<String, String> map = new HashMap<String, String>();
    List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map.entrySet());
    Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
    @Override
    public int compare(Map.Entry<String, String> mapping1, Map.Entry<String, String> mapping2) {
    return mapping1.getKey().compareTo(mapping2.getKey());
    }
    });
  1. TreeMap默认按key进行升序排序,如果想改变默认的顺序,可以使用比较器:

    1
    2
    3
    4
    5
    6
    7
    Map<String, String> map = new TreeMap<String, String>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
    // 降序排序
    return o1.compareTo(o2);
    }
    });

    按想要的 value 值排序,也要先用ArrayList 构造函数把entrySet() 转化为 list,再用collections 的比较器来比较:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Map<String, String> map = new TreeMap<String, String>();
    List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map.entrySet());

    Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
    @Override
    public int compare(Map.Entry<String, String> mapping1, Map.Entry<String, String> mapping2) {
    return mapping1.getValue().compareTo(mapping2.getValue());
    }
    });

参考

https://juejin.im/post/5ad40593f265da23750759ad