Java集合

Java集合

    • 一、什么是Java集合?
      • 主要组成部分:
    • 二、Collections工具类
      • 1. **排序相关方法**:
      • 2. **查找和替换相关方法**:
      • 3. **同步和不可变集合相关方法**:
      • 4. **打乱顺序相关方法**:
      • 5. **集合频率与填充相关方法**:
      • 6. **集合比较相关方法**:
      • 7. **集合旋转相关方法**:
      • 8. **集合交换相关方法**:
      • 9. **集合填充相关方法**:
      • 10. **空集合相关方法**:
    • 三、集合类中线程安全的实现
      • 1. **`Vector` 和 `Hashtable`**
      • 2. **`Collections.synchronizedXXX()` 方法**
      • 3. **`ConcurrentHashMap`**
      • 4. **`CopyOnWriteArrayList` 和 `CopyOnWriteArraySet`**
      • 5. **`BlockingQueue`(如 `LinkedBlockingQueue`、`ArrayBlockingQueue`)**
      • 6. **`ConcurrentSkipListMap` 和 `ConcurrentSkipListSet`**
      • 总结:
    • 四、Java集合类实战
      • 1. **ArrayList 实战:动态数组**
      • 2. **HashSet 实战:去重和无序集合**
      • 3. **HashMap 实战:键值对存储**
      • 4. **LinkedList 实战:双向链表**
      • 5. **TreeSet 实战:有序集合**
      • 6. **PriorityQueue 实战:优先级队列**
      • 总结

一、什么是Java集合?

Java集合(Java Collections)是Java中用于存储、操作和管理一组对象的数据结构框架。它提供了一套接口和类,帮助开发者以统一的方式处理各种类型的集合,如列表、集合、队列和映射。Java集合框架使得开发者可以轻松地处理数据结构,不需要自己实现复杂的数据结构算法。

主要组成部分:

  1. 核心接口

    • Collection:这是最基本的集合接口,它提供了一些通用的集合操作方法,如添加、删除、遍历等。ListSetQueue接口都继承自Collection
      • List:有序集合,允许重复元素。例如:ArrayListLinkedList
      • Set:无序集合,不允许重复元素。例如:HashSetTreeSet
      • Queue:队列,遵循FIFO(先进先出)原则,例如:PriorityQueue
      • Deque:双端队列,支持在两端插入和删除元素,例如:ArrayDeque
  2. Map接口

    • Map:并不继承Collection,但也是Java集合框架的一部分。它存储键值对,每个键都唯一。例如:HashMapTreeMapLinkedHashMap
  3. 重要实现类

    • ArrayList:基于动态数组的List实现,查找元素速度快,增删效率相对较慢。
    • LinkedList:基于链表的List实现,增删速度快,查找效率较低。
    • HashSet:基于哈希表实现的Set,不保证元素顺序。
    • TreeSet:基于红黑树实现的Set,元素是有序的。
    • HashMap:基于哈希表实现的Map,允许null键和null值。
    • TreeMap:基于红黑树实现的Map,键按自然顺序或自定义比较器排序。
  4. Collections工具类

    • 提供了对集合操作的实用方法,例如排序、查找、同步化集合等功能。

Java集合框架通过使用泛型,提供了类型安全的集合操作,从而避免了在运行时发生类型转换错误。

你可以根据需要选择不同的集合类型来存储和操作数据。

二、Collections工具类

Java中的Collections工具类是一个包含多个静态方法的实用类,提供了对集合进行各种操作的工具。通过Collections类,你可以执行排序、查找、同步化、打乱顺序等操作。以下是Collections工具类的一些常用方法:

1. 排序相关方法

  • sort(List list):对List集合中的元素进行升序排序,要求集合中的元素实现Comparable接口。
  • sort(List list, Comparator c):使用指定的ComparatorList集合中的元素进行排序。
  • reverse(List list):将List中的元素顺序反转。

2. 查找和替换相关方法

  • binarySearch(List> list, T key):使用二分查找算法在有序List中查找元素,返回元素的索引。
  • binarySearch(List list, T key, Comparator c):使用二分查找算法和自定义比较器查找元素。
  • max(Collection coll):返回集合中的最大元素,要求集合中的元素实现Comparable接口。
  • max(Collection coll, Comparator comp):使用指定的Comparator,返回集合中的最大元素。
  • min(Collection coll):返回集合中的最小元素。
  • min(Collection coll, Comparator comp):使用指定的Comparator,返回集合中的最小元素。
  • replaceAll(List list, T oldVal, T newVal):将List中的所有oldVal替换为newVal

3. 同步和不可变集合相关方法

  • synchronizedList(List list):返回一个线程安全的List
  • synchronizedSet(Set s):返回一个线程安全的Set
  • synchronizedMap(Map m):返回一个线程安全的Map
  • unmodifiableList(List list):返回一个不可修改的List
  • unmodifiableSet(Set set):返回一个不可修改的Set
  • unmodifiableMap(Map m):返回一个不可修改的Map

4. 打乱顺序相关方法

  • shuffle(List list):随机打乱List集合中的元素顺序。
  • shuffle(List list, Random rnd):使用指定的随机数生成器打乱List中的元素顺序。

5. 集合频率与填充相关方法

  • frequency(Collection c, Object o):返回指定元素在集合中出现的次数。
  • fill(List list, T obj):将List中的所有元素都替换为指定的元素。
  • copy(List dest, List src):将src中的所有元素复制到dest中,要求dest至少与src的大小相等。

6. 集合比较相关方法

  • disjoint(Collection c1, Collection c2):如果两个集合没有交集,则返回true
  • nCopies(int n, T o):返回包含no元素的不可修改列表。

7. 集合旋转相关方法

  • rotate(List list, int distance):将List中的元素按照指定距离旋转(正值右移,负值左移)。

8. 集合交换相关方法

  • swap(List list, int i, int j):交换List中索引i和索引j处的元素。

9. 集合填充相关方法

  • addAll(Collection c, T... elements):向集合中添加多个元素。
  • singleton(T o):返回一个只包含单一对象的不可修改Set
  • singletonList(T o):返回一个只包含单一对象的不可修改List
  • singletonMap(K key, V value):返回一个只包含单一键值对的不可修改Map

10. 空集合相关方法

  • emptyList():返回一个空的不可修改List
  • emptySet():返回一个空的不可修改Set
  • emptyMap():返回一个空的不可修改Map

这些方法为开发者提供了丰富的集合操作手段,能够简化集合的处理工作,同时确保代码的简洁性和可读性。

三、集合类中线程安全的实现

在 Java 集合框架中,实现线程安全的集合类有多种方式。下面是几种常见的线程安全实现:

1. VectorHashtable

  • 早期的集合类如 VectorHashtable 本身是线程安全的,因为它们的方法都使用了 synchronized 关键字。
  • 这些类的缺点是性能较低,因为每个方法调用都会加锁,即使在没有竞争的情况下也会导致性能开销。

2. Collections.synchronizedXXX() 方法

  • 通过 Collections.synchronizedXXX() 方法,可以将非线程安全的集合(如 ArrayListHashMap 等)转换为线程安全的版本。

  • 例如:

    List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
    Map<String, String> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
    
  • 这种方法会对整个集合的访问加锁,但需要注意的是,遍历集合时仍然需要手动同步:

    synchronized(synchronizedList) {
        for (String item : synchronizedList) {
            // Do something with item
        }
    }
    
  • 这种实现方法的优点是可以让你灵活地使用各种集合类,但由于它对每个方法调用加锁,性能可能较低。

3. ConcurrentHashMap

  • ConcurrentHashMapHashMap 的线程安全版本,它使用了一种更高效的并发控制机制,允许多线程在不同的分段(segment)上并发读写,而不需要锁整个集合。

  • 相比 Collections.synchronizedMapConcurrentHashMap 在并发性能上有显著提升,尤其是读多写少的场景。

  • 例如:

    Map<String, String> concurrentMap = new ConcurrentHashMap<>();
    
  • ConcurrentHashMap 还引入了一些额外的并发操作方法,如 putIfAbsent()computeIfAbsent() 等。

4. CopyOnWriteArrayListCopyOnWriteArraySet

  • CopyOnWriteArrayListCopyOnWriteArraySet 是基于写时复制(Copy-On-Write)的集合类,适用于读操作远多于写操作的场景。

  • 每次写操作都会复制底层数组,写操作性能较低,但读操作不需要加锁,性能非常高。

  • 例如:

    List<String> cowList = new CopyOnWriteArrayList<>();
    Set<String> cowSet = new CopyOnWriteArraySet<>();
    

5. BlockingQueue(如 LinkedBlockingQueueArrayBlockingQueue

  • BlockingQueue 是线程安全的队列实现,适用于生产者-消费者模型。它提供了阻塞的 put()take() 方法,用于线程之间安全地共享数据。
  • 常见的实现包括 LinkedBlockingQueueArrayBlockingQueue 等。

6. ConcurrentSkipListMapConcurrentSkipListSet

  • 这两个类是线程安全的、基于跳表的数据结构,它们是有序集合,可以用在需要线程安全且有序的场景中。

  • 例如:

    Map<String, String> skipListMap = new ConcurrentSkipListMap<>();
    Set<String> skipListSet = new ConcurrentSkipListSet<>();
    

总结:

  • 如果是读多写少的场景,可以考虑 CopyOnWriteArrayList
  • 如果需要高效的并发访问并且不需要严格的同步控制,ConcurrentHashMap 是一个很好的选择。
  • 如果需要简单的线程安全集合,可以使用 Collections.synchronizedXXX()
  • 对于队列模型,BlockingQueue 是非常合适的选择。

四、Java集合类实战

Java 集合类是 Java 编程中的基础工具之一,用于存储和操作一组对象。集合类提供了多种不同的数据结构和算法,包括列表、集合、映射等。下面将通过几个常见的集合类的实际应用场景,介绍它们的使用。

1. ArrayList 实战:动态数组

场景:需要存储一个可变长度的元素列表,并且对顺序进行严格的管理。

示例代码

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        
        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.add("Orange");

        // 遍历列表
        for (String fruit : list) {
            System.out.println(fruit);
        }

        // 获取元素
        String firstFruit = list.get(0);
        System.out.println("First Fruit: " + firstFruit);

        // 删除元素
        list.remove("Banana");
        System.out.println("After removal: " + list);
    }
}

适用场景:当需要频繁读取元素且元素顺序重要时,ArrayList 是理想的选择。

2. HashSet 实战:去重和无序集合

场景:需要存储一组不重复的元素,并且不关心元素的顺序。

示例代码

import java.util.HashSet;
import java.util.Set;

public class HashSetExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        
        // 添加元素
        set.add("Apple");
        set.add("Banana");
        set.add("Orange");
        set.add("Apple"); // 重复的元素不会被添加

        // 遍历集合
        for (String fruit : set) {
            System.out.println(fruit);
        }
        
        // 判断是否包含某个元素
        boolean containsApple = set.contains("Apple");
        System.out.println("Contains Apple? " + containsApple);
    }
}

适用场景:需要避免重复元素时,HashSet 是最佳选择。

3. HashMap 实战:键值对存储

场景:需要将一组键值对进行存储和快速检索。

示例代码

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        
        // 添加键值对
        map.put("Apple", 10);
        map.put("Banana", 20);
        map.put("Orange", 30);

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

        // 获取特定键对应的值
        int applePrice = map.get("Apple");
        System.out.println("Price of Apple: " + applePrice);

        // 删除键值对
        map.remove("Banana");
        System.out.println("After removal: " + map);
    }
}

适用场景:需要通过键快速查找数据时,HashMap 是常用选择。

4. LinkedList 实战:双向链表

场景:需要频繁对集合的两端进行操作(如插入和删除)。

示例代码

import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        
        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.addFirst("Orange");  // 在头部插入
        list.addLast("Grape");    // 在尾部插入

        // 遍历列表
        for (String fruit : list) {
            System.out.println(fruit);
        }

        // 删除元素
        list.removeFirst();  // 删除头部
        list.removeLast();   // 删除尾部
        System.out.println("After removal: " + list);
    }
}

适用场景:当需要频繁在列表头尾操作时,LinkedList 具有更高的性能。

5. TreeSet 实战:有序集合

场景:需要存储一组不重复且有序的元素。

示例代码

import java.util.TreeSet;

public class TreeSetExample {
    public static void main(String[] args) {
        TreeSet<String> set = new TreeSet<>();
        
        // 添加元素
        set.add("Banana");
        set.add("Apple");
        set.add("Orange");

        // 遍历集合(自动按字典顺序排序)
        for (String fruit : set) {
            System.out.println(fruit);
        }

        // 获取最小和最大元素
        System.out.println("First: " + set.first());
        System.out.println("Last: " + set.last());
    }
}

适用场景:需要存储有序元素时,TreeSet 是理想的选择。

6. PriorityQueue 实战:优先级队列

场景:需要按优先级顺序处理任务或元素。

示例代码

import java.util.PriorityQueue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        
        // 添加元素
        queue.add(10);
        queue.add(20);
        queue.add(5);

        // 处理元素(自动按升序排列)
        while (!queue.isEmpty()) {
            System.out.println(queue.poll());
        }
    }
}

适用场景:需要按优先级处理任务时,PriorityQueue 非常适合。

总结

Java 集合类为我们提供了多种处理不同数据需求的工具。在实际开发中,选择合适的集合类不仅可以提高程序性能,还可以让代码更加简洁和可读。

你可能感兴趣的:(后端,java,集合框架,Java集合,线程安全)