Java集合框架:数据存储与操作的利器

引言

Java集合框架是Java语言中用于存储和操作数据的一组核心接口和实现类。它提供了一套标准化的方法来处理各种数据结构,使开发人员能够专注于业务逻辑而不是底层数据结构的实现。本文将深入探讨Java集合框架的各个组成部分,并通过实例展示如何高效地使用它们。

一、集合框架概览

1.1 集合框架层次结构

Java集合框架主要分为两大分支:

  • Collection接口:单列数据集合,包括List、Set和Queue

  • Map接口:双列数据集合,存储键值对

java

复制代码
// 集合框架主要接口关系图
// Collection (接口)
//   ├── List (接口)
//   │    ├── ArrayList (实现类)
//   │    ├── LinkedList (实现类)
//   │    └── Vector (实现类,线程安全)
//   │         └── Stack (子类)
//   ├── Set (接口)
//   │    ├── HashSet (实现类)
//   │    │    └── LinkedHashSet (子类)
//   │    └── TreeSet (实现类)
//   └── Queue (接口)
//        ├── PriorityQueue (实现类)
//        └── Deque (接口)
//             └── ArrayDeque (实现类)
//
// Map (接口)
//   ├── HashMap (实现类)
//   │    └── LinkedHashMap (子类)
//   ├── TreeMap (实现类)
//   └── Hashtable (实现类,线程安全)
//        └── Properties (子类)

1.2 集合框架的优势

  1. 标准化:统一的API设计,易于学习和使用

  2. 高性能:针对不同场景优化的实现

  3. 类型安全:通过泛型确保类型安全

  4. 可扩展:易于扩展和自定义实现

  5. 算法支持:内置排序、搜索等算法

二、Collection接口及其实现

2.1 List接口:有序、可重复的集合

java

复制代码
import java.util.*;

public class ListExample {
    public static void main(String[] args) {
        // 1. ArrayList - 基于动态数组,随机访问快
        List<String> arrayList = new ArrayList<>();
        arrayList.add("Java");
        arrayList.add("Python");
        arrayList.add("C++");
        arrayList.add(1, "JavaScript"); // 在指定位置插入
        
        System.out.println("ArrayList内容: " + arrayList);
        System.out.println("第二个元素: " + arrayList.get(1));
        System.out.println("元素数量: " + arrayList.size());
        
        // ArrayList的遍历方式
        System.out.println("\nArrayList遍历:");
        // 方式1:普通for循环
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.print(arrayList.get(i) + " ");
        }
        
        // 方式2:增强for循环
        System.out.println("\n增强for循环:");
        for (String language : arrayList) {
            System.out.print(language + " ");
        }
        
        // 方式3:迭代器
        System.out.println("\n迭代器遍历:");
        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next() + " ");
        }
        
        // 方式4:Lambda表达式(Java 8+)
        System.out.println("\nLambda表达式遍历:");
        arrayList.forEach(lang -> System.out.print(lang + " "));
        
        // 方式5:方法引用
        System.out.println("\n方法引用遍历:");
        arrayList.forEach(System.out::print);
        
        // 2. LinkedList - 基于双向链表,插入删除快
        List<Integer> linkedList = new LinkedList<>();
        linkedList.add(10);
        linkedList.add(20);
        linkedList.add(30);
        linkedList.addFirst(5);  // 在开头添加
        linkedList.addLast(40);  // 在末尾添加
        
        System.out.println("\n\nLinkedList内容: " + linkedList);
        System.out.println("第一个元素: " + ((LinkedList<Integer>) linkedList).getFirst());
        System.out.println("最后一个元素: " + ((LinkedList<Integer>) linkedList).getLast());
        
        // LinkedList作为队列使用
        Queue<Integer> queue = new LinkedList<>(linkedList);
        System.out.println("\n队列操作:");
        System.out.println("队首元素: " + queue.peek());
        System.out.println("出队元素: " + queue.poll());
        System.out.println("剩余队列: " + queue);
        
        // LinkedList作为栈使用
        Deque<Integer> stack = new LinkedList<>();
        stack.push(1);  // 入栈
        stack.push(2);
        stack.push(3);
        System.out.println("\n栈操作:");
        System.out.println("栈顶元素: " + stack.peek());
        System.out.println("出栈元素: " + stack.pop());
        System.out.println("剩余栈: " + stack);
        
        // 3. Vector - 线程安全的ArrayList(已过时,不推荐使用)
        List<String> vector = new Vector<>();
        vector.add("线程安全");
        vector.add("但不推荐使用");
        System.out.println("\nVector: " + vector);
    }
}

2.2 Set接口:无序、不可重复的集合

java

复制代码
import java.util.*;

public class SetExample {
    public static void main(String[] args) {
        // 1. HashSet - 基于哈希表,无序
        Set<String> hashSet = new HashSet<>();
        hashSet.add("Apple");
        hashSet.add("Banana");
        hashSet.add("Orange");
        hashSet.add("Apple"); // 重复元素不会被添加
        
        System.out.println("HashSet: " + hashSet);
        System.out.println("包含Banana? " + hashSet.contains("Banana"));
        System.out.println("Set大小: " + hashSet.size());
        
        // 2. LinkedHashSet - 保持插入顺序的HashSet
        Set<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("第一");
        linkedHashSet.add("第二");
        linkedHashSet.add("第三");
        linkedHashSet.add("第一"); // 不会重复添加
        
        System.out.println("\nLinkedHashSet: " + linkedHashSet);
        
        // 3. TreeSet - 基于红黑树,自动排序
        Set<Integer> treeSet = new TreeSet<>();
        treeSet.add(5);
        treeSet.add(2);
        treeSet.add(8);
        treeSet.add(1);
        treeSet.add(5); // 不会重复添加
        
        System.out.println("\nTreeSet(自然排序): " + treeSet);
        
        // 自定义排序的TreeSet
        Set<String> customTreeSet = new TreeSet<>((s1, s2) -> 
            s2.compareTo(s1)); // 降序排序
        customTreeSet.add("Java");
        customTreeSet.add("Python");
        customTreeSet.add("C++");
        
        System.out.println("TreeSet(自定义降序): " + customTreeSet);
        
        // Set操作:交集、并集、差集
        Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
        Set<Integer> set2 = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));
        
        // 并集
        Set<Integer> union = new HashSet<>(set1);
        union.addAll(set2);
        System.out.println("\n并集: " + union);
        
        // 交集
        Set<Integer> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        System.out.println("交集: " + intersection);
        
        // 差集(set1 - set2)
        Set<Integer> difference = new HashSet<>(set1);
        difference.removeAll(set2);
        System.out.println("差集(set1-set2): " + difference);
    }
}

2.3 Queue接口:队列实现

java

复制代码
import java.util.*;

public class QueueExample {
    public static void main(String[] args) {
        // 1. PriorityQueue - 优先级队列
        Queue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(5);
        priorityQueue.offer(1);
        priorityQueue.offer(3);
        priorityQueue.offer(2);
        priorityQueue.offer(4);
        
        System.out.println("PriorityQueue元素: " + priorityQueue);
        System.out.println("按优先级出队:");
        while (!priorityQueue.isEmpty()) {
            System.out.print(priorityQueue.poll() + " ");
        }
        
        // 自定义优先级的PriorityQueue
        Queue<String> customPriorityQueue = new PriorityQueue<>(
            (s1, s2) -> s2.length() - s1.length() // 按字符串长度降序
        );
        customPriorityQueue.offer("Java");
        customPriorityQueue.offer("Python");
        customPriorityQueue.offer("C");
        customPriorityQueue.offer("JavaScript");
        
        System.out.println("\n\n按字符串长度优先级出队:");
        while (!customPriorityQueue.isEmpty()) {
            System.out.print(customPriorityQueue.poll() + " ");
        }
        
        // 2. ArrayDeque - 双端队列
        Deque<String> deque = new ArrayDeque<>();
        deque.addFirst("前端");  // 添加到队首
        deque.addLast("后端");   // 添加到队尾
        deque.offerFirst("移动端");
        deque.offerLast("数据库");
        
        System.out.println("\n\nArrayDeque内容: " + deque);
        System.out.println("队首元素: " + deque.peekFirst());
        System.out.println("队尾元素: " + deque.peekLast());
        System.out.println("移除队首: " + deque.pollFirst());
        System.out.println("移除队尾: " + deque.pollLast());
        System.out.println("剩余队列: " + deque);
        
        // 使用ArrayDeque作为栈
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(10);  // 入栈
        stack.push(20);
        stack.push(30);
        System.out.println("\nArrayDeque作为栈:");
        System.out.println("栈顶元素: " + stack.peek());
        System.out.println("出栈: " + stack.pop());
        System.out.println("出栈后: " + stack);
    }
}

三、Map接口及其实现

java

复制代码
import java.util.*;

public class MapExample {
    public static void main(String[] args) {
        // 1. HashMap - 最常用的Map实现
        Map<String, Integer> hashMap = new HashMap<>();
        hashMap.put("Java", 95);
        hashMap.put("Python", 90);
        hashMap.put("C++", 88);
        hashMap.put("Java", 96); // 更新已有键的值
        hashMap.putIfAbsent("JavaScript", 92); // 仅当键不存在时放入
        
        System.out.println("HashMap内容: " + hashMap);
        System.out.println("Java的分数: " + hashMap.get("Java"));
        System.out.println("包含Python键? " + hashMap.containsKey("Python"));
        System.out.println("包含分数90? " + hashMap.containsValue(90));
        System.out.println("Map大小: " + hashMap.size());
        
        // HashMap遍历方式
        System.out.println("\nHashMap遍历:");
        
        // 方式1:遍历键集合
        System.out.println("遍历键:");
        for (String key : hashMap.keySet()) {
            System.out.println(key + ": " + hashMap.get(key));
        }
        
        // 方式2:遍历值集合
        System.out.println("\n遍历值:");
        for (Integer value : hashMap.values()) {
            System.out.println(value);
        }
        
        // 方式3:遍历键值对集合
        System.out.println("\n遍历键值对:");
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // 方式4:迭代器遍历
        System.out.println("\n迭代器遍历:");
        Iterator<Map.Entry<String, Integer>> iterator = 
            hashMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Integer> entry = iterator.next();
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // 方式5:Lambda表达式(Java 8+)
        System.out.println("\nLambda表达式遍历:");
        hashMap.forEach((key, value) -> 
            System.out.println(key + ": " + value));
        
        // 2. LinkedHashMap - 保持插入顺序的HashMap
        Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("第一", 1);
        linkedHashMap.put("第二", 2);
        linkedHashMap.put("第三", 3);
        
        System.out.println("\nLinkedHashMap(保持插入顺序): " + linkedHashMap);
        
        // 3. TreeMap - 基于红黑树,按键排序
        Map<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("Orange", 3);
        treeMap.put("Apple", 5);
        treeMap.put("Banana", 2);
        
        System.out.println("\nTreeMap(按键排序): " + treeMap);
        
        // 自定义排序的TreeMap
        Map<String, Integer> customTreeMap = new TreeMap<>(
            (s1, s2) -> s2.compareTo(s1) // 降序排序
        );
        customTreeMap.put("Java", 95);
        customTreeMap.put("Python", 90);
        customTreeMap.put("C++", 88);
        
        System.out.println("TreeMap(自定义降序): " + customTreeMap);
        
        // Map操作示例
        System.out.println("\nMap操作示例:");
        
        // 获取或默认值
        int javaScore = hashMap.getOrDefault("Java", 0);
        int rubyScore = hashMap.getOrDefault("Ruby", 0);
        System.out.println("Java分数: " + javaScore);
        System.out.println("Ruby分数(默认0): " + rubyScore);
        
        // 替换值
        hashMap.replace("Python", 90, 95);
        System.out.println("替换后Python分数: " + hashMap.get("Python"));
        
        // 合并值
        hashMap.merge("Java", 2, (oldValue, newValue) -> oldValue + newValue);
        System.out.println("合并后Java分数: " + hashMap.get("Java"));
        
        // 计算值(如果键不存在)
        hashMap.computeIfAbsent("Go", k -> 85);
        System.out.println("Go分数: " + hashMap.get("Go"));
        
        // 删除键
        hashMap.remove("C++");
        System.out.println("删除C++后: " + hashMap);
    }
}

四、集合工具类:Collections和Arrays

java

复制代码
import java.util.*;

public class CollectionsExample {
    public static void main(String[] args) {
        // 创建测试数据
        List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));
        List<String> fruits = new ArrayList<>(Arrays.asList(
            "Apple", "Banana", "Orange", "Grape", "Mango"
        ));
        
        // 1. 排序操作
        System.out.println("原始列表: " + numbers);
        Collections.sort(numbers);
        System.out.println("排序后: " + numbers);
        
        // 自定义排序
        Collections.sort(fruits, (s1, s2) -> s2.compareTo(s1)); // 降序
        System.out.println("水果降序: " + fruits);
        
        // 2. 查找操作
        int index = Collections.binarySearch(numbers, 8);
        System.out.println("\n元素8的索引: " + index);
        
        // 3. 反转和随机排序
        Collections.reverse(numbers);
        System.out.println("反转后: " + numbers);
        
        Collections.shuffle(numbers);
        System.out.println("随机排序后: " + numbers);
        
        // 4. 最大最小值
        System.out.println("最大值: " + Collections.max(numbers));
        System.out.println("最小值: " + Collections.min(numbers));
        
        // 5. 填充和复制
        List<Integer> copy = new ArrayList<>(Collections.nCopies(5, 0));
        System.out.println("\n填充5个0: " + copy);
        
        Collections.fill(copy, 1);
        System.out.println("填充为1后: " + copy);
        
        // 6. 不可变集合
        List<String> unmodifiableList = 
            Collections.unmodifiableList(fruits);
        System.out.println("\n不可变列表: " + unmodifiableList);
        
        // 7. 同步集合(线程安全)
        List<String> synchronizedList = 
            Collections.synchronizedList(new ArrayList<>());
        synchronizedList.add("线程安全");
        System.out.println("同步列表: " + synchronizedList);
        
        // 8. Arrays工具类使用
        int[] array = {5, 2, 8, 1, 9};
        System.out.println("\n原始数组: " + Arrays.toString(array));
        
        Arrays.sort(array);
        System.out.println("排序后数组: " + Arrays.toString(array));
        
        int[] filledArray = new int[5];
        Arrays.fill(filledArray, 7);
        System.out.println("填充数组: " + Arrays.toString(filledArray));
        
        int[] copyArray = Arrays.copyOf(array, 3);
        System.out.println("复制前3个元素: " + Arrays.toString(copyArray));
    }
}

五、Java 8+新特性:Stream API

java

复制代码
import java.util.*;
import java.util.stream.*;

public class StreamExample {
    public static void main(String[] args) {
        List<String> languages = Arrays.asList(
            "Java", "Python", "JavaScript", "C++", "Go", "Ruby", "Swift"
        );
        
        // 1. 过滤和收集
        List<String> filtered = languages.stream()
            .filter(lang -> lang.startsWith("J"))  // 过滤以J开头的
            .collect(Collectors.toList());          // 收集到List
            
        System.out.println("以J开头的语言: " + filtered);
        
        // 2. 映射转换
        List<String> upperCase = languages.stream()
            .map(String::toUpperCase)               // 转为大写
            .collect(Collectors.toList());
            
        System.out.println("大写语言: " + upperCase);
        
        // 3. 排序
        List<String> sorted = languages.stream()
            .sorted()                               // 自然排序
            .collect(Collectors.toList());
            
        System.out.println("排序后: " + sorted);
        
        // 4. 限制和跳过
        List<String> limited = languages.stream()
            .limit(3)                               // 取前3个
            .collect(Collectors.toList());
            
        System.out.println("前3个语言: " + limited);
        
        // 5. 统计操作
        long count = languages.stream()
            .filter(lang -> lang.length() > 3)
            .count();
            
        System.out.println("长度大于3的语言数量: " + count);
        
        // 6. 查找操作
        Optional<String> first = languages.stream()
            .filter(lang -> lang.length() > 5)
            .findFirst();
            
        first.ifPresent(lang -> 
            System.out.println("第一个长度大于5的语言: " + lang));
        
        // 7. 去重
        List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
        List<Integer> distinct = numbers.stream()
            .distinct()                             // 去重
            .collect(Collectors.toList());
            
        System.out.println("去重后: " + distinct);
        
        // 8. 规约操作
        Optional<Integer> sum = numbers.stream()
            .reduce(Integer::sum);                  // 求和
            
        sum.ifPresent(s -> System.out.println("总和: " + s));
        
        // 9. 分组操作
        Map<Integer, List<String>> grouped = languages.stream()
            .collect(Collectors.groupingBy(String::length));
            
        System.out.println("按长度分组: " + grouped);
        
        // 10. 并行流
        List<String> parallelResult = languages.parallelStream()
            .filter(lang -> lang.length() > 2)
            .map(String::toUpperCase)
            .sorted()
            .collect(Collectors.toList());
            
        System.out.println("并行流处理结果: " + parallelResult);
    }
}

六、最佳实践和性能优化

6.1 集合选择指南

需求 推荐实现类 理由
快速随机访问 ArrayList 基于数组,O(1)访问
频繁插入删除 LinkedList 基于链表,O(1)插入删除
需要排序 TreeSet/TreeMap 自动排序
需要唯一元素 HashSet/HashMap 基于哈希表,O(1)查找
需要保持插入顺序 LinkedHashSet/LinkedHashMap 保持插入顺序
线程安全需求 CopyOnWriteArrayList, ConcurrentHashMap 并发安全

6.2 性能优化建议

java

复制代码
import java.util.*;

public class PerformanceTips {
    public static void main(String[] args) {
        // 1. 指定初始容量
        List<String> list = new ArrayList<>(1000); // 避免频繁扩容
        Map<String, Integer> map = new HashMap<>(1000, 0.75f);
        
        // 2. 使用增强for循环而非迭代器
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        
        // 推荐:增强for循环
        for (Integer num : numbers) {
            System.out.print(num + " ");
        }
        
        // 3. 使用entrySet遍历Map
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Java", 95);
        scores.put("Python", 90);
        
        // 推荐:遍历entrySet
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // 不推荐:遍历keySet再get
        for (String key : scores.keySet()) {
            System.out.println(key + ": " + scores.get(key)); // 两次查找
        }
        
        // 4. 批量操作
        List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> target = new ArrayList<>(source.size());
        
        // 推荐:批量添加
        target.addAll(source);
        
        // 5. 使用不可变集合
        List<String> immutableList = List.of("A", "B", "C"); // Java 9+
        Set<String> immutableSet = Set.of("A", "B", "C");
        Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);
        
        // 6. 并发场景使用并发集合
        Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
        concurrentMap.put("Key1", 1);
        concurrentMap.putIfAbsent("Key2", 2);
    }
}

七、常见问题与解决方案

7.1 集合的线程安全问题

java

复制代码
import java.util.*;
import java.util.concurrent.*;

public class ThreadSafeCollections {
    public static void main(String[] args) throws InterruptedException {
        // 1. 非线程安全的HashMap
        Map<String, Integer> unsafeMap = new HashMap<>();
        
        // 2. 使用Collections.synchronizedMap包装
        Map<String, Integer> synchronizedMap = 
            Collections.synchronizedMap(new HashMap<>());
        
        // 3. 使用ConcurrentHashMap(推荐)
        Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
        
        // 测试线程安全
        ExecutorService executor = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            final int index = i;
            executor.execute(() -> {
                concurrentMap.put("key" + index, index);
            });
        }
        
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.SECONDS);
        
        System.out.println("ConcurrentHashMap大小: " + concurrentMap.size());
        
        // 4. CopyOnWriteArrayList用于读多写少的场景
        List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
        copyOnWriteList.add("Java");
        copyOnWriteList.add("Python");
        
        // 迭代时安全,但写操作开销大
        for (String item : copyOnWriteList) {
            System.out.println(item);
        }
    }
}

7.2 避免ConcurrentModificationException

java

复制代码
import java.util.*;

public class ConcurrentModificationFix {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList(
            "Java", "Python", "C++", "JavaScript"
        ));
        
        // 错误示例:在迭代时修改集合
        try {
            for (String lang : list) {
                if (lang.equals("C++")) {
                    list.remove(lang); // 抛出ConcurrentModificationException
                }
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("错误:迭代时修改集合");
        }
        
        // 正确方法1:使用迭代器的remove方法
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String lang = iterator.next();
            if (lang.equals("C++")) {
                iterator.remove(); // 安全删除
            }
        }
        System.out.println("方法1处理后: " + list);
        
        // 正确方法2:使用Java 8+的removeIf
        list.add("C++"); // 恢复数据
        list.removeIf(lang -> lang.equals("C++"));
        System.out.println("方法2处理后: " + list);
        
        // 正确方法3:收集要删除的元素,最后统一删除
        list.add("C++"); // 恢复数据
        List<String> toRemove = new ArrayList<>();
        for (String lang : list) {
            if (lang.equals("C++")) {
                toRemove.add(lang);
            }
        }
        list.removeAll(toRemove);
        System.out.println("方法3处理后: " + list);
    }
}

总结

Java集合框架是Java编程中最重要的组成部分之一,掌握好集合框架的使用对于编写高效、可维护的代码至关重要。本文详细介绍了各种集合类的特点、使用场景和最佳实践:

  1. 根据需求选择合适的集合类

  2. 理解不同集合的性能特征

  3. 掌握集合的遍历和操作技巧

  4. 注意线程安全和并发修改问题

  5. 善用Java 8+的新特性如Stream API

记住,没有"最好"的集合,只有"最适合"的集合。在实际开发中,根据具体需求选择合适的集合实现,才能真正发挥集合框架的威力。

学习建议:

  • 深入理解各种集合的内部实现原理

  • 掌握Java 8+的Lambda表达式和Stream API

  • 学习并发集合的使用场景

  • 了解Java版本更新中集合框架的新特性

希望这篇博客能帮助您全面掌握Java集合框架,提升编程效率!

相关推荐
virus594529 分钟前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
初次见面我叫泰隆42 分钟前
Qt——3、常用控件
开发语言·qt·客户端
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
宝宝单机sop1 小时前
Ai 算法资源合集
经验分享
计算机小手1 小时前
一个带Web UI管理的轻量级高性能OpenAI模型代理网关,支持Docker快速部署
经验分享·docker·语言模型·开源软件
没差c2 小时前
springboot集成flyway
java·spring boot·后端
三水不滴2 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
无小道2 小时前
Qt——QWidget
开发语言·qt
时艰.2 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
其古寺2 小时前
Spring事务嵌套异常处理深度解析
经验分享