java集合框架

一、引言
  • Java 集合框架概述
    • 定义和重要性
      Java 集合框架是一个提供了表示和操作集合数据结构的标准化 API 的库。它是 Java 程序设计语言中非常重要的一部分,用于存储、检索、操纵和传输数据。集合框架极大地简化了编程过程,通过提供预定义的数据结构和算法,开发者可以更加专注于业务逻辑,而不是数据结构的实现细节。

    • 集合框架的组成部分
      Java 集合框架主要由以下几个部分组成:

      • 接口:定义了集合操作的基本合同。常见的接口包括 Collection、List、Set、Map、Queue 等。

      • 实现类:这些是接口的具体实现。常见的实现类包括 ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap 等。

      • 算法:算法是定义在集合上的方法,例如排序、搜索和修改集合。Java 提供了 Collections 类来实现这些算法。

      • 实用工具类:如 Collections 和 Arrays 类,提供了各种集合操作的静态方法,如排序、搜索、同步控制等。

二、集合框架的基本接口
  • Collection 接口
    Collection接口是Java集合框架的根接口,所有集合类都直接或间接实现了这个接口。它定义了一些基本操作,如添加、删除和检查集合的大小等。

    基本方法:

    • add(E e): 添加元素到集合中。
    • remove(Object o): 从集合中移除指定元素。
    • size(): 返回集合中元素的个数。
    • isEmpty(): 检查集合是否为空。
    • iterator(): 返回一个迭代器,用于遍历集合中的元素。

示例:

import java.util.ArrayList;
import java.util.Collection;

public class CollectionExample {
    public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("Hello");
        collection.add("World");
        System.out.println("Collection size: " + collection.size());
        System.out.println("Is collection empty? " + collection.isEmpty());
        for (String item : collection) {
            System.out.println(item);
        }
    }
}

  • List 接口
    List接口是Collection的子接口,表示一个有序的元素集合,允许重复元素。
    • 常用实现类:

      • ArrayList:基于动态数组的实现。
      • LinkedList:基于双向链表的实现。
      • VectorStack:线程安全的实现。
    • 基本方法:

      • get(int index): 获取指定索引处的元素。
      • set(int index, E element): 替换指定索引处的元素。
      • add(int index, E element): 在指定位置插入元素。
      • remove(int index): 移除指定位置的元素。
      • indexOf(Object o): 返回指定元素第一次出现的位置。

示例:

import java.util.ArrayList;
import java.util.Collection;

public class CollectionExample {
    public static void main(String[] args) {
        Collection<String> collection = new ArrayList<>();
        collection.add("Hello");
        collection.add("World");
        System.out.println("Collection size: " + collection.size());
        System.out.println("Is collection empty? " + collection.isEmpty());
        for (String item : collection) {
            System.out.println(item);
        }
    }
}

  • Set 接口

    Set接口是Collection的子接口,表示一个不包含重复元素的集合。

    基本方法:与Collection接口相同,因为Set不允许重复元素,所以add()方法会返回false,如果试图添加的元素已经存在。add()方法通过hashCode和equals方法来判断元素是否相等。

    • 常见实现类
      • HashSet:基于哈希表的实现。
      • LinkedHashSet:维护插入顺序的哈希表实现。
      • TreeSet:基于红黑树的实现,保证元素的自然顺序。

示例:

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

public class SetExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("Hello");
        set.add("World");
        set.add("Hello"); // 尝试添加重复元素
        System.out.println("Set size: " + set.size());
        for (String item : set) {
            System.out.println(item);
        }
    }
}

  • Queue 接口

    Queue接口是Collection的子接口,表示一个先进先出的队列。

    • 常见实现类
      • PriorityQueue:基于优先级堆的实现。
      • Deque(双端队列):如ArrayDequeLinkedList,允许在两端插入和移除元素。
    • 基本方法
      • offer(E e): 向队列添加元素。
      • poll(): 获取并移除队列的头元素。
      • peek(): 获取但不移除队列的头元素。

示例:

import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        queue.offer("Hello");
        queue.offer("World");
        System.out.println("Queue size: " + queue.size());
        System.out.println("Peek: " + queue.peek());
        System.out.println("Poll: " + queue.poll());
        System.out.println("Queue size after poll: " + queue.size());
    }
}

三、Map 接口

Map接口不属于Collection接口体系,它表示一个键值对映射。每个键唯一对应一个值。

  • Map 接口
    • 常见实现类
      • HashMap:基于哈希表的实现。
      • LinkedHashMap:维护插入顺序的哈希表实现。
      • TreeMap:基于红黑树的实现,保证键的自然顺序。
      • Hashtable:线程安全的哈希表实现。
      • ConcurrentHashMap:支持高并发的哈希表实现。
    • 基本方法
      • put(K key, V value): 添加键值对。
      • get(Object key): 获取键对应的值。
      • remove(Object key): 移除键对应的键值对。
      • containsKey(Object key): 检查是否包含指定的键。
      • keySet(): 获取所有键的集合。

示例:

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

public class MapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("Alice", 30);
        map.put("Bob", 25);
        System.out.println("Map size: " + map.size());
        System.out.println("Alice's age: " + map.get("Alice"));
        map.remove("Alice");
        System.out.println("Map size after removal: " + map.size());
    }
}

四、集合框架的实用工具类
  • Collections 类
    • Collections 类是一个操作集合的工具类,提供了一些静态方法来处理和操作集合。以下是一些常用的 Collections类方法及其简要说明:
      • 排序sort(List<T> list) - 对指定列表按升序排序。
      • 反转reverse(List<?> list) - 反转指定列表中元素的顺序。
      • 随机打乱shuffle(List<?> list) - 随机打乱指定列表的顺序。
      • 查找binarySearch(List<? extends Comparable<? super T>> list, T key) - 使用二分搜索算法查找指定列表中的元素。
      • 最小/最大min(Collection<? extends T> coll)max(Collection<? extends T> coll) - 返回指定集合中的最小/最大元素。
      • 同步控制synchronizedList(List<T> list) - 返回一个线程安全的列表。
      • 不可变集合unmodifiableList(List<? extends T> list) - 返回一个不可变的列表。

示例:

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

public class CollectionsExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Banana");
        list.add("Apple");
        list.add("Cherry");

        // 排序
        Collections.sort(list);
        System.out.println("Sorted list: " + list);

        // 反转
        Collections.reverse(list);
        System.out.println("Reversed list: " + list);

        // 查找
        int index = Collections.binarySearch(list, "Banana");
        System.out.println("Index of Banana: " + index);

        // 随机打乱
        Collections.shuffle(list);
        System.out.println("Shuffled list: " + list);
    }
}

  • Arrays 类

    Arrays 类是一个包含用来操作数组(如排序和搜索)的各种方法的工具类。以下是一些常用的 Arrays 类方法及其简要说明:

    • 转换为列表asList(T... a) - 将数组转换为固定大小的列表。
    • 排序sort(T[] a) - 对指定数组按升序排序。
    • 二分查找binarySearch(T[] a, T key) - 使用二分搜索算法查找指定数组中的元素。
    • 填充fill(T[] a, T val) - 将指定值分配给数组中的每个元素。
    • 比较equals(T[] a, T[] a2) - 判断两个数组是否相等。
    • 复制copyOf(T[] original, int newLength) - 复制指定数组,截取或填充以适应新的长度。

示例:

import java.util.Arrays;

public class ArraysExample {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 8, 2};

        // 排序
        Arrays.sort(numbers);
        System.out.println("Sorted array: " + Arrays.toString(numbers));

        // 二分查找
        int index = Arrays.binarySearch(numbers, 3);
        System.out.println("Index of 3: " + index);

        // 填充
        int[] filledArray = new int[5];
        Arrays.fill(filledArray, 10);
        System.out.println("Filled array: " + Arrays.toString(filledArray));

        // 复制
        int[] copiedArray = Arrays.copyOf(numbers, 6);
        System.out.println("Copied array: " + Arrays.toString(copiedArray));
    }
}

五、集合框架的高级特性
  • 泛型

    Java 的集合框架广泛使用泛型,以确保类型安全并减少强制类型转换的需要。泛型允许在声明集合时指定集合中元素的类型,从而在编译时提供类型检查。

    • 泛型的定义和使用

      泛型在声明时使用尖括号 <> 指定类型参数。例如,ArrayList<String> 表示一个存储 String 类型元素的列表。

示例:

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

public class GenericsExample {
    public static void main(String[] args) {
        // 使用泛型声明一个字符串列表
        List<String> stringList = new ArrayList<>();
        stringList.add("Hello");
        stringList.add("World");

        // 编译时检查类型
        // stringList.add(123); // 编译错误,类型不匹配

        for (String s : stringList) {
            System.out.println(s);
        }
    }
}

  • 迭代器

    迭代器用于遍历集合中的元素。Java 提供了 IteratorListIterator 接口。

    • Iterator 接口
      • hasNext(): 如果迭代器还有更多元素,则返回 true
      • next(): 返回迭代器的下一个元素。
      • remove(): 从迭代器指向的集合中移除最后一个返回的元素。
    • ListIterator 接口:除了 Iterator 的所有功能外,还增加了双向遍历功能。
      • hasPrevious(): 如果有前一个元素,则返回 true
      • previous(): 返回前一个元素。

示例:

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

public class IteratorExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            if ("Banana".equals(fruit)) {
                iterator.remove();
            } else {
                System.out.println(fruit);
            }
        }
    }
}

  • Stream API

    Stream API 提供了一种高效且易于使用的方式来处理集合数据(类似于SQL语句)。Stream 可以执行过滤、映射、排序和聚合等操作。(对于集合来说十分好用。推荐使用Stream来对集合进行操作,推荐一个我觉得写的好的博客:https://www.cnblogs.com/owenma/p/12207330.html

    • Stream 的创建和操作
      • stream(): 创建一个顺序流。
      • parallelStream(): 创建一个并行流。
    • 中间操作与终端操作
      • 中间操作(如 filter, map)返回新的 Stream,允许链式调用。
      • 终端操作(如 collect, forEach, reduce)触发 Stream 的执行并返回结果。

示例:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class StreamExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // 使用 Stream 过滤和收集结果
        List<String> filteredList = list.stream()
                                        .filter(s -> s.startsWith("A"))
                                        .collect(Collectors.toList());

        filteredList.forEach(System.out::println);
    }
}

  • 集合框架中的比较器

    Java 提供了 ComparableComparator 接口,用于定义集合元素的自然顺序和定制顺序。

    • Comparable:定义元素的自然顺序,通过实现 compareTo 方法。
    • Comparator:用于定义自定义顺序,通过实现 compare 方法。

示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Person implements Comparable<Person> {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Person other) {
        return this.age - other.age;
    }

    @Override
    public String toString() {
        return name + ": " + age;
    }
}

public class ComparatorExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 使用 Comparable 进行排序
        Collections.sort(people);
        System.out.println("Sorted by age: " + people);

        // 使用 Comparator 进行自定义排序
        people.sort(Comparator.comparing(p -> p.name));
        System.out.println("Sorted by name: " + people);
    }
}

六、集合框架的性能和优化
  • 不同集合的性能比较
    • ArrayList vs LinkedList
    • ArrayList
      • 优势:基于数组,提供快速的随机访问(时间复杂度 O(1))。
      • 劣势:在中间插入或删除元素时性能较差(时间复杂度 O(n))。
      • 适用场景:适用于频繁读取元素或在列表末尾添加元素的场景。
    • LinkedList
      • 优势:基于链表,在列表中间插入和删除元素时性能较好(时间复杂度 O(1))。
      • 劣势:随机访问性能较差(时间复杂度 O(n))。
      • 适用场景:适用于频繁在列表中间插入或删除元素的场景。

示例:

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

public class ListPerformanceExample {
    public static void main(String[] args) {
        List<Integer> arrayList = new ArrayList<>();
        List<Integer> linkedList = new LinkedList<>();

        // 添加元素到 ArrayList 和 LinkedList
        for (int i = 0; i < 100000; i++) {
            arrayList.add(i);
            linkedList.add(i);
        }

        // 测试 ArrayList 随机访问性能
        long startTime = System.nanoTime();
        arrayList.get(50000);
        long endTime = System.nanoTime();
        System.out.println("ArrayList get time: " + (endTime - startTime) + " ns");

        // 测试 LinkedList 随机访问性能
        startTime = System.nanoTime();
        linkedList.get(50000);
        endTime = System.nanoTime();
        System.out.println("LinkedList get time: " + (endTime - startTime) + " ns");
    }
}

  • HashSet vs TreeSet
    • HashSet
      • 优势:基于哈希表,提供快速的插入、删除和查找操作(平均时间复杂度 O(1))。
      • 劣势:不保证元素的顺序。
      • 适用场景:适用于需要快速查找、不关心元素顺序的场景。
    • TreeSet
      • 优势:基于红黑树,保证元素的自然顺序或定制顺序(时间复杂度 O(log n))。
      • 劣势:插入、删除和查找操作比 HashSet 慢。
      • 适用场景:适用于需要有序集合的场景。

示例:

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

public class SetPerformanceExample {
    public static void main(String[] args) {
        Set<Integer> hashSet = new HashSet<>();
        Set<Integer> treeSet = new TreeSet<>();

        // 添加元素到 HashSet 和 TreeSet
        for (int i = 0; i < 100000; i++) {
            hashSet.add(i);
            treeSet.add(i);
        }

        // 测试 HashSet 查找性能
        long startTime = System.nanoTime();
        hashSet.contains(50000);
        long endTime = System.nanoTime();
        System.out.println("HashSet contains time: " + (endTime - startTime) + " ns");

        // 测试 TreeSet 查找性能
        startTime = System.nanoTime();
        treeSet.contains(50000);
        endTime = System.nanoTime();
        System.out.println("TreeSet contains time: " + (endTime - startTime) + " ns");
    }
}

  • HashMap vs TreeMap
    • HashMap
      • 优势:基于哈希表,提供快速的插入、删除和查找操作(平均时间复杂度 O(1))。
      • 劣势:不保证键的顺序。
      • 适用场景:适用于需要快速查找、不关心键顺序的场景。
    • TreeMap
      • 优势:基于红黑树,保证键的自然顺序或定制顺序(时间复杂度 O(log n))。
      • 劣势:插入、删除和查找操作比 HashMap 慢。
      • 适用场景:适用于需要有序键值对的场景。

示例:

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

public class MapPerformanceExample {
    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        Map<Integer, String> treeMap = new TreeMap<>();

        // 添加元素到 HashMap 和 TreeMap
        for (int i = 0; i < 100000; i++) {
            hashMap.put(i, "value" + i);
            treeMap.put(i, "value" + i);
        }

        // 测试 HashMap 查找性能
        long startTime = System.nanoTime();
        hashMap.get(50000);
        long endTime = System.nanoTime();
        System.out.println("HashMap get time: " + (endTime - startTime) + " ns");

        // 测试 TreeMap 查找性能
        startTime = System.nanoTime();
        treeMap.get(50000);
        endTime = System.nanoTime();
        System.out.println("TreeMap get time: " + (endTime - startTime) + " ns");
    }
}

  • 集合的线程安全

    Java 提供了一些工具类来将非线程安全的集合转换为线程安全的集合。

    • Collections.synchronizedXXX() 方法
      • java.util.Collections 类提供了若干静态方法,可以将标准的集合类包装成线程安全的集合。例如:
        • Collections.synchronizedList(List<T> list)
        • Collections.synchronizedSet(Set<T> s)
        • Collections.synchronizedMap(Map<K, V> m)
    • 使用 java.util.concurrent 包中的集合类
      • ConcurrentHashMap:是一个线程安全的哈希表,允许多个线程并发读取,并且在某些条件下允许多个线程并发写入。
      • CopyOnWriteArrayList:是一种线程安全的变体数组列表,所有修改操作(如 addset)都会创建一个新的内部数组,因此读操作无需同步。
      • CopyOnWriteArraySet:基于 CopyOnWriteArrayList 实现的线程安全的 Set。

​ 为了确保集合在多线程环境下的安全性,可以使用 Collections.synchronizedXXX() 方法将集合包装为线程安全的版本,或者直接使用 java.util.concurrent 包中的并发集合类。对于更复杂的场景,可以使用显式锁来控制对集合的访问。选择具体的实现时,应根据应用程序的具体需求、性能考虑和使用场景来决定。

七、集合框架的常见使用模式
  • 集合的遍历和操作

    • 单列数据(List)
    Map<String, Integer> hashMap = new HashMap<>();
    Map<String, Integer> treeMap = new TreeMap<>();
    
    hashMap.put("one", 1);
    hashMap.put("two", 2);
    hashMap.put("three", 3);
    // 使用 keySet 遍历键
    for (String key : hashMap.keySet()) {
        System.out.println(key + " -> " + hashMap.get(key));
    }
    
    // 使用 entrySet 遍历键值对
    for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
        System.out.println(entry.getKey() + " -> " + entry.getValue());
    }
    
    // 使用 forEach 方法(Java 8 及以上)
    hashMap.forEach((key, value) -> {
        System.out.println(key + " -> " + value);
    });
    
    
    • 双列数据(将Map转换为Set才能使用迭代器,Map本身没有迭代器)
    Map<String, Integer> hashMap = new HashMap<>();
    Map<String, Integer> treeMap = new TreeMap<>();
    
    hashMap.put("one", 1);
    hashMap.put("two", 2);
    hashMap.put("three", 3);
    // 使用 keySet 遍历键
    for (String key : hashMap.keySet()) {
        System.out.println(key + " -> " + hashMap.get(key));
    }
    
    // 使用 entrySet 遍历键值对
    for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
        System.out.println(entry.getKey() + " -> " + entry.getValue());
    }
    
    // 使用 forEach 方法(Java 8 及以上)
    hashMap.forEach((key, value) -> {
        System.out.println(key + " -> " + value);
    });
    
    
  • 集合的转换

    1. List 转 Set(去除重复元素)
    List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three", "one"));
    Set<String> set = new HashSet<>(list);
    System.out.println(set);  // 输出: [one, two, three]
    
    
    1. Set转List(保留集合元素的顺序或访问元素时使用索引)
    Set<String> set = new HashSet<>(Arrays.asList("one", "two", "three"));
    List<String> list = new ArrayList<>(set);
    System.out.println(list);  // 输出: [one, two, three]
    
    
    1. List转Map(将列表转换为键值对映射,通常需要提供键值的生成规则)
    List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three"));
    Map<String, Integer> map = list.stream().collect(Collectors.toMap(
        Function.identity(), 
        String::length
    ));
    System.out.println(map);  // 输出: {one=3, two=3, three=5}
    
    
    1. Map转List(将键或值提取为列表)
    Map<String, Integer> map = new HashMap<>();
    map.put("one", 1);
    map.put("two", 2);
    map.put("three", 3);
    
    // 提取键
    List<String> keys = new ArrayList<>(map.keySet());
    System.out.println(keys);  // 输出: [one, two, three]
    
    // 提取值
    List<Integer> values = new ArrayList<>(map.values());
    System.out.println(values);  // 输出: [1, 2, 3]
    
    
    1. 数组转List(方便使用集合操作)
    String[] array = {"one", "two", "three"};
    List<String> list = Arrays.asList(array);
    System.out.println(list);  // 输出: [one, two, three]
    
    //注意:Arrays.asList 返回的列表是固定大小的,不能添加或删除元素。如果需要一个可变大小的列表,可以使用以下方式
    List<String> list = new ArrayList<>(Arrays.asList(array));
    list.add("four");
    System.out.println(list);  // 输出: [one, two, three, four]
    
    ```java
    
    6. List转数组(需要时转换)
    
    ```java
    List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three"));
    String[] array = list.toArray(new String[0]);
    System.out.println(Arrays.toString(array));  // 输出: [one, two, three]
    
    
    1. Set转Map(将集合转换为映射,通常需要提供键值的生成规则)
    Set<String> set = new HashSet<>(Arrays.asList("one", "two", "three"));
    Map<String, Integer> map = set.stream().collect(Collectors.toMap(
        Function.identity(), 
        String::length
    ));
    System.out.println(map);  // 输出: {one=3, two=3, three=5}
    
    
    1. Map转Set(将键或值转为集合)
    Map<String, Integer> map = new HashMap<>();
    map.put("one", 1);
    map.put("two", 2);
    map.put("three", 3);
    
    // 提取键
    Set<String> keySet = map.keySet();
    System.out.println(keySet);  // 输出: [one, two, three]
    
    // 提取值
    Set<Integer> valueSet = new HashSet<>(map.values());
    System.out.println(valueSet);  // 输出: [1, 2, 3]
    
八、总结

​ Java 集合框架是一个功能丰富、灵活且高效的数据结构和算法库。通过合理地选择和使用集合框架中的各个组件,可以极大地简化编程任务,提高代码的可读性和运行效率。掌握集合框架的使用是每个 Java 开发者的必备技能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值