Java 集合框架高级应用与架构设计方案
作者:星河耀银海
一、章节学习目标与重点
1.1 学习目标
- 掌握集合框架在复杂架构场景中的高级应用(缓存设计、分层存储、数据分片)
- 理解集合与设计模式的结合实践(享元模式、装饰器模式、迭代器模式等)
- 精通高并发、大数据量场景下集合的架构优化方案
- 解决集合在分布式、微服务架构中的适配问题
- 能够基于集合框架设计可扩展、高性能的核心业务组件
1.2 学习重点
- 基于集合的缓存架构设计(本地缓存、多级缓存)
- 集合与设计模式的深度融合实践
- 大数据量下集合的分片存储与并行处理架构
- 分布式场景中集合的数据一致性与传输优化
- 集合框架驱动的业务组件设计(配置中心、规则引擎)
二、基于集合的缓存架构设计实战
💡 缓存是提升系统性能的核心手段,而 Java 集合框架是实现本地缓存的基础。基于集合的缓存设计需兼顾查询效率、内存占用、过期策略、线程安全四大核心诉求,常用集合包括 HashMap、LinkedHashMap、WeakHashMap 等。
2.1 本地缓存设计核心要素
- 存储结构:选择合适的集合实现类(如 HashMap 用于高效查询,LinkedHashMap 用于 LRU 过期策略)
- 过期策略:支持时间过期(TTL)、空间淘汰(LRU/LFU)
- 线程安全:高并发场景需保证读写安全
- 内存控制:避免缓存膨胀,支持自动回收无用数据
2.2 基于 LinkedHashMap 的 LRU 缓存实现(固定容量+TTL)
LinkedHashMap 天然支持访问顺序维护,结合 removeEldestEntry() 方法可实现 LRU 淘汰,扩展后支持 TTL 过期策略:
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
/**
* 基于 LinkedHashMap 的 LRU+TTL 本地缓存
* 特性:固定容量(LRU 淘汰)、时间过期(TTL)、线程安全
*/
public class LruTtlCache<K, V> extends LinkedHashMap<K, CacheEntry<V>> {
private final int maxCapacity; // 最大容量
private final long ttlMillis; // 过期时间(毫秒)
private final ReentrantLock lock = new ReentrantLock(); // 可重入锁保证线程安全
// 缓存条目:包装值和过期时间
private static class CacheEntry<V> {
V value;
long expireTime; // 过期时间戳(毫秒)
CacheEntry(V value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}
// 判断是否过期
boolean isExpired() {
return System.currentTimeMillis() > expireTime;
}
}
// 构造函数:指定最大容量和 TTL
public LruTtlCache(int maxCapacity, long ttlMillis) {
super(maxCapacity, 0.75f, true); // accessOrder=true(访问顺序)
this.maxCapacity = maxCapacity;
this.ttlMillis = ttlMillis;
}
/**
* 重写 removeEldestEntry:达到最大容量时删除最久未使用的条目
*/
@Override
protected boolean removeEldestEntry(Map.Entry<K, CacheEntry<V>> eldest) {
// 先清理过期条目
if (eldest.getValue().isExpired()) {
return true;
}
// 未过期则判断是否超容量
return size() > maxCapacity;
}
/**
* 存缓存:线程安全
*/
public void put(K key, V value) {
Objects.requireNonNull(key);
Objects.requireNonNull(value);
lock.lock();
try {
// 计算过期时间戳
long expireTime = System.currentTimeMillis() + ttlMillis;
super.put(key, new CacheEntry<>(value, expireTime));
} finally {
lock.unlock();
}
}
/**
* 取缓存:线程安全,自动过滤过期条目
*/
public V get(Object key) {
lock.lock();
try {
CacheEntry<V> entry = super.get(key);
if (entry == null) {
return null;
}
// 过期则删除并返回 null
if (entry.isExpired()) {
super.remove(key);
return null;
}
return entry.value;
} finally {
lock.unlock();
}
}
/**
* 批量清理过期条目
*/
public void cleanExpired() {
lock.lock();
try {
keySet().removeIf(key -> super.get(key).isExpired());
} finally {
lock.unlock();
}
}
}2.3 多级缓存架构设计(本地缓存+分布式缓存)
在微服务架构中,单一本地缓存无法满足分布式部署需求,需设计“本地缓存+分布式缓存”的多级架构:
2.3.1 架构示意图
应用服务 A 应用服务 B
┌───────────────┐ ┌───────────────┐
│ 本地缓存 │ │ 本地缓存 │
│ (LruTtlCache)│ │ (LruTtlCache)│
└───────┬───────┘ └───────┬───────┘
│ │
└───────────┬───────────┘
│
┌───────▼───────┐
│ 分布式缓存 │
│ (Redis) │
└───────┬───────┘
│
┌───────▼───────┐
│ 数据库 │
└───────────────┘2.3.2 核心逻辑
- 读取数据:优先查本地缓存 → 本地未命中查分布式缓存 → 分布式未命中查数据库,查询结果回写两级缓存
- 更新数据:更新数据库 → 淘汰分布式缓存 → 淘汰所有应用节点的本地缓存(通过消息通知)
- 优势:本地缓存提升响应速度,分布式缓存保证分布式一致性,数据库保证数据持久化
2.3.3 代码简化实现(多级缓存客户端)
import redis.clients.jedis.Jedis;
import java.util.function.Supplier;
/**
* 多级缓存客户端(本地缓存+Redis)
*/
public class MultiLevelCache<K, V> {
private final LruTtlCache<K, V> localCache;
private final Jedis redisClient;
private final String prefix; // Redis 键前缀
private final long redisTtlSeconds; // Redis 过期时间(秒)
// 构造函数:初始化各级缓存
public MultiLevelCache(int localMaxCapacity, long localTtlMillis,
Jedis redisClient, String prefix, long redisTtlSeconds) {
this.localCache = new LruTtlCache<>(localMaxCapacity, localTtlMillis);
this.redisClient = redisClient;
this.prefix = prefix;
this.redisTtlSeconds = redisTtlSeconds;
}
/**
* 读取缓存:自动降级查询
* @param key 缓存键
* @param loader 数据库加载器(缓存未命中时执行)
* @return 缓存值
*/
public V get(K key, Supplier<V> loader) {
// 1. 查本地缓存
V value = localCache.get(key);
if (value != null) {
return value;
}
// 2. 查 Redis 缓存
String redisKey = prefix + key;
String redisValue = redisClient.get(redisKey);
if (redisValue != null) {
V deserialized = deserialize(redisValue); // 反序列化
localCache.put(key, deserialized); // 回写本地缓存
return deserialized;
}
// 3. 查数据库并回写缓存
value = loader.get();
if (value != null) {
localCache.put(key, value);
redisClient.setex(redisKey, redisTtlSeconds, serialize(value)); // 序列化并设置过期时间
}
return value;
}
/**
* 淘汰缓存:更新数据时调用
*/
public void evict(K key) {
localCache.remove(key); // 淘汰本地缓存
redisClient.del(prefix + key); // 淘汰 Redis 缓存
// 发送消息通知其他节点淘汰本地缓存(如 RocketMQ/Kafka)
sendEvictMessage(key);
}
// 序列化/反序列化(简化实现,实际可使用 Jackson)
private String serialize(V value) {
return value.toString();
}
private V deserialize(String value) {
return (V) value;
}
// 发送缓存淘汰消息(简化实现)
private void sendEvictMessage(K key) {
System.out.println("发送缓存淘汰消息:" + key);
}
}2.4 缓存架构优化要点
- 本地缓存:使用 LruTtlCache 控制内存,定期清理过期数据,避免内存泄漏
- 分布式缓存:选择 Redis 等高性能组件,设置合理 TTL,避免缓存雪崩
- 一致性保障:更新数据时采用“更新数据库→淘汰缓存”顺序,结合消息通知实现分布式缓存一致性
- 降级策略:分布式缓存不可用时,仅依赖本地缓存+数据库,保证系统可用性
三、集合与设计模式的深度融合实践
Java 集合框架本身大量运用设计模式(如迭代器模式、装饰器模式),在实际开发中,结合设计模式使用集合可大幅提升代码的扩展性和可维护性。
3.1 装饰器模式+集合:增强集合功能
装饰器模式通过包装原集合,在不修改原代码的前提下增强功能(如日志记录、权限控制、数据校验)。以下实现一个“带访问日志的 List”:
import java.util.*;
/**
* 装饰器模式:带访问日志的 List
*/
public class LoggingList<E> implements List<E> {
// 被装饰的原 List
private final List<E> target;
// 日志记录器(简化实现)
private final Logger logger = new Logger();
// 构造函数:传入原 List
public LoggingList(List<E> target) {
this.target = Objects.requireNonNull(target);
}
/**
* 增强 add 方法:记录添加日志
*/
@Override
public boolean add(E e) {
logger.log("添加元素:" + e);
return target.add(e);
}
/**
* 增强 get 方法:记录访问日志
*/
@Override
public E get(int index) {
E e = target.get(index);
logger.log("访问索引 " + index + " 的元素:" + e);
return e;
}
/**
* 其他方法直接委托给原 List(省略重复代码,实际开发可通过 IDE 自动生成)
*/
@Override
public int size() {
return target.size();
}
@Override
public boolean isEmpty() {
return target.isEmpty();
}
// ... 其他 List 接口方法(均委托给 target)
/**
* 简化日志类
*/
private static class Logger {
public void log(String message) {
System.out.println("[LoggingList] " + message);
}
}
// 测试
public static void main(String[] args) {
List<String> list = new LoggingList<>(new ArrayList<>());
list.add("Java");
list.add("集合");
list.get(0);
// 输出:
// [LoggingList] 添加元素:Java
// [LoggingList] 添加元素:集合
// [LoggingList] 访问索引 0 的元素:Java
}
}3.2 享元模式+集合:复用重复对象
享元模式通过缓存重复对象减少内存占用,适用于大量相似对象场景(如配置项、常量、商品规格)。以下基于 HashMap 实现享元池:
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 享元模式:商品规格享元池(复用重复的规格对象)
*/
public class SpecificationFlyweightPool {
// 享元池:缓存规格对象(key=规格编码,value=规格对象)
private static final Map<String, Specification> POOL = new HashMap<>();
/**
* 获取规格对象:存在则复用,不存在则创建并缓存
*/
public static Specification getSpecification(String color, String size) {
Objects.requireNonNull(color);
Objects.requireNonNull(size);
// 生成唯一编码(作为享元池 key)
String key = color + "_" + size;
// 双重检查锁定(DCL)保证线程安全
if (!POOL.containsKey(key)) {
synchronized (SpecificationFlyweightPool.class) {
if (!POOL.containsKey(key)) {
POOL.put(key, new Specification(color, size));
}
}
}
return POOL.get(key);
}
/**
* 商品规格类(不可变,确保享元安全复用)
*/
public static class Specification {
private final String color;
private final String size;
private Specification(String color, String size) {
this.color = color;
this.size = size;
}
// getter(无 setter,确保不可变)
public String getColor() {
return color;
}
public String getSize() {
return size;
}
// 重写 equals 和 hashCode(确保 key 唯一性)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Specification that = (Specification) o;
return Objects.equals(color, that.color) && Objects.equals(size, that.size);
}
@Override
public int hashCode() {
return Objects.hash(color, size);
}
}
// 测试:复用对象
public static void main(String[] args) {
Specification spec1 = getSpecification("红色", "M");
Specification spec2 = getSpecification("红色", "M");
System.out.println(spec1 == spec2); // true(复用同一对象)
}
}3.3 迭代器模式+集合:自定义遍历逻辑
迭代器模式隔离集合的存储结构与遍历逻辑,支持自定义遍历规则(如过滤、分页、排序)。以下实现一个“分页迭代器”:
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
/**
* 迭代器模式:分页迭代器(按页遍历集合)
*/
public class PagingIterator<E> implements Iterator<List<E>> {
private final List<E> source; // 源集合
private final int pageSize; // 每页大小
private int currentPage; // 当前页码(从 0 开始)
private final int totalPages; // 总页数
/**
* 构造函数:传入源集合和每页大小
*/
public PagingIterator(List<E> source, int pageSize) {
this.source = Objects.requireNonNull(source);
if (pageSize <= 0) {
throw new IllegalArgumentException("每页大小必须大于 0");
}
this.pageSize = pageSize;
this.currentPage = 0;
// 计算总页数
this.totalPages = (source.size() + pageSize - 1) / pageSize;
}
/**
* 是否还有下一页
*/
@Override
public boolean hasNext() {
return currentPage < totalPages;
}
/**
* 获取下一页数据
*/
@Override
public List<E> next() {
if (!hasNext()) {
throw new NoSuchElementException("没有更多页面");
}
// 计算当前页的起始索引和结束索引
int start = currentPage * pageSize;
int end = Math.min(start + pageSize, source.size());
List<E> pageData = source.subList(start, end);
currentPage++;
return pageData;
}
// 测试:分页遍历 10 条数据(每页 3 条)
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
PagingIterator<Integer> iterator = new PagingIterator<>(list, 3);
int pageNum = 1;
while (iterator.hasNext()) {
List<Integer> page = iterator.next();
System.out.println("第 " + pageNum + " 页:" + page);
pageNum++;
}
// 输出:
// 第 1 页:[1, 2, 3]
// 第 2 页:[4, 5, 6]
// 第 3 页:[7, 8, 9]
// 第 4 页:[10]
}
}四、大数据量下集合的分片存储与并行处理
当数据量达到百万、千万级别时,单一集合会面临内存溢出、遍历效率低等问题,需采用“分片存储+并行处理”架构,利用多线程和分布式资源提升处理能力。
4.1 集合分片存储设计(基于 List 的分片)
将大数据量集合拆分为多个小分片(Shard),每个分片存储部分数据,便于并行处理和内存控制:
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 集合分片工具类:将大 List 拆分为多个小分片
*/
public class ListSharder<T> {
private final List<T> source; // 源集合
private final int shardSize; // 每个分片的最大大小
public ListSharder(List<T> source, int shardSize) {
this.source = Objects.requireNonNull(source);
if (shardSize <= 0) {
throw new IllegalArgumentException("分片大小必须大于 0");
}
this.shardSize = shardSize;
}
/**
* 执行分片:返回分片列表
*/
public List<List<T>> shard() {
List<List<T>> shards = new ArrayList<>();
int totalSize = source.size();
if (totalSize == 0) {
return shards;
}
// 计算分片数量
int shardCount = (totalSize + shardSize - 1) / shardSize;
for (int i = 0; i < shardCount; i++) {
// 计算当前分片的起始和结束索引
int start = i * shardSize;
int end = Math.min(start + shardSize, totalSize);
// 截取分片并添加到结果集(ArrayList 是线程不安全的,并行处理时需注意)
List<T> shard = new ArrayList<>(source.subList(start, end));
shards.add(shard);
}
return shards;
}
// 测试:将 100 万条数据拆分为每个分片 1 万条
public static void main(String[] args) {
// 生成 100 万条测试数据
List<Integer> bigList = new ArrayList<>(1_000_000);
for (int i = 0; i < 1_000_000; i++) {
bigList.add(i);
}
// 分片(每个分片 10000 条)
ListSharder<Integer> sharder = new ListSharder<>(bigList, 10_000);
List<List<Integer>> shards = sharder.shard();
System.out.println("总数据量:" + bigList.size());
System.out.println("分片数量:" + shards.size());
System.out.println("每个分片大小:" + shards.get(0).size());
// 输出:
// 总数据量:1000000
// 分片数量:100
// 每个分片大小:10000
}
}4.2 分片并行处理(基于线程池)
将分片分配给线程池并行处理,利用多核 CPU 资源提升处理效率,适用于数据筛选、统计、转换等场景:
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 分片并行处理器:基于线程池处理分片数据
*/
public class ShardParallelProcessor<T, R> {
private final ExecutorService executor; // 线程池
private final int threadCount; // 线程数(默认 CPU 核心数)
// 构造函数:默认线程数为 CPU 核心数
public ShardParallelProcessor() {
this.threadCount = Runtime.getRuntime().availableProcessors();
this.executor = Executors.newFixedThreadPool(threadCount);
}
// 构造函数:自定义线程数
public ShardParallelProcessor(int threadCount) {
this.threadCount = threadCount;
this.executor = Executors.newFixedThreadPool(threadCount);
}
/**
* 并行处理分片:每个分片执行 processor 逻辑
* @param shards 分片列表
* @param processor 分片处理逻辑(函数式接口)
* @return 合并后的处理结果
*/
public List<R> process(List<List<T>> shards, ShardProcessor<T, R> processor) {
try {
// 提交所有分片任务,并行执行
return shards.stream()
.map(shard -> executor.submit(() -> processor.process(shard)))
.map(future -> {
try {
return future.get(); // 获取分片处理结果
} catch (Exception e) {
throw new RuntimeException("分片处理失败", e);
}
})
.flatMap(List::stream) // 合并所有分片结果
.collect(Collectors.toList());
} finally {
// 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(1, TimeUnit.HOURS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}
/**
* 分片处理函数式接口
*/
@FunctionalInterface
public interface ShardProcessor<T, R> {
List<R> process(List<T> shard);
}
// 测试:并行统计分片数据中偶数的个数
public static void main(String[] args) {
// 1. 生成 100 万条数据并分片
List<Integer> bigList = new ArrayList<>(1_000_000);
for (int i = 0; i < 1_000_000; i++) {
bigList.add(i);
}
ListSharder<Integer> sharder = new ListSharder<>(bigList, 10_000);
List<List<Integer>> shards = sharder.shard();
// 2. 并行处理:统计每个分片的偶数个数
ShardParallelProcessor<Integer, Integer> processor = new ShardParallelProcessor<>();
List<Integer> shardEvenCounts = processor.process(shards, shard -> {
// 每个分片统计偶数个数
long count = shard.stream().filter(num -> num % 2 == 0).count();
return List.of((int) count);
});
// 3. 合并结果
int totalEvenCount = shardEvenCounts.stream().mapToInt(Integer::intValue).sum();
System.out.println("100 万条数据中偶数的个数:" + totalEvenCount); // 输出:500000
}
}4.3 分布式分片处理(基于 MapReduce 思想)
当数据量达到亿级别时,单机分片已无法满足需求,需采用分布式分片架构(如 Hadoop MapReduce、Spark),核心思想:
- 分片:将分布式存储(如 HDFS、MySQL 分库分表)中的数据拆分为多个分片
- 映射(Map):多个节点并行处理各自分片,输出中间结果
- 归约(Reduce):汇总所有节点的中间结果,得到最终结果
Java 集合可作为分布式分片的“本地处理单元”,配合分布式框架实现大规模数据处理。
五、分布式场景中集合的数据一致性与传输优化
在分布式系统中,集合数据的传输和一致性维护是核心挑战,需解决“数据序列化、网络传输效率、分布式一致性”三大问题。
5.1 集合数据序列化优化
集合数据在网络中传输时需序列化,选择高效的序列化框架可降低传输开销,常用框架包括:
- Jackson:JSON 序列化,可读性强,适用于中小数据量
- Protostuff:二进制序列化,效率高、体积小,适用于大数据量
- Kryo:高性能二进制序列化,适用于分布式缓存、RPC 传输
以下是基于 Protostuff 的集合序列化工具类:
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.util.List;
import java.util.Map;
/**
* 集合序列化工具类(基于 Protostuff)
*/
public class CollectionSerializer {
// 线程局部变量:避免缓冲区竞争
private static final ThreadLocal<LinkedBuffer> BUFFER = ThreadLocal.withInitial(() -> LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
/**
* 序列化 List
*/
public static <T> byte[] serializeList(List<T> list, Class<T> clazz) {
if (list == null || list.isEmpty()) {
return new byte[0];
}
Schema<T> schema = RuntimeSchema.getSchema(clazz);
LinkedBuffer buffer = BUFFER.get();
try {
return ProtostuffIOUtil.toByteArray(list, schema, buffer);
} finally {
buffer.clear(); // 清空缓冲区
}
}
/**
* 反序列化 List
*/
public static <T> List<T> deserializeList(byte[] data, Class<T> clazz) {
if (data == null || data.length == 0) {
return List.of();
}
Schema<T> schema = RuntimeSchema.getSchema(clazz);
List<T> list = schema.newMessage().getClass().isAssignableFrom(List.class) ?
(List<T>) schema.newMessage() : new ArrayList<>();
ProtostuffIOUtil.mergeFrom(data, (T) list, schema);
return list;
}
/**
* 序列化 Map(简化实现,实际需自定义 Schema)
*/
public static <K, V> byte[] serializeMap(Map<K, V> map, Class<K> keyClazz, Class<V> valueClazz) {
// 实际开发中需为 Map 自定义 Schema,此处简化为 JSON 序列化(仅作示例)
try {
return new com.alibaba.fastjson.JSONObject().toJSONBytes(map);
} catch (Exception e) {
throw new RuntimeException("Map 序列化失败", e);
}
}
/**
* 反序列化 Map
*/
public static <K, V> Map<K, V> deserializeMap(byte[] data, Class<K> keyClazz, Class<V> valueClazz) {
if (data == null || data.length == 0) {
return Map.of();
}
// 对应序列化逻辑,简化为 JSON 反序列化
try {
return com.alibaba.fastjson.JSONObject.parseObject(data, new com.alibaba.fastjson.TypeReference<Map<K, V>>() {});
} catch (Exception e) {
throw new RuntimeException("Map 反序列化失败", e);
}
}
}5.2 分布式集合数据一致性保障
分布式场景中,多个节点同时操作集合数据会导致一致性问题,常用解决方案:
- 分布式锁:通过 Redis 分布式锁、ZooKeeper 锁等,保证同一时间只有一个节点修改数据
- 版本控制:为集合数据添加版本号,修改时校验版本,避免覆盖过期数据
- 最终一致性:基于消息队列异步同步数据,允许短时间不一致,最终达到一致
以下是基于 Redis 分布式锁的集合修改示例:
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 分布式集合修改:基于 Redis 分布式锁保证一致性
*/
public class DistributedListModifier<T> {
private final Jedis jedis;
private final String listKey; // Redis 中 List 的 key
private final String lockKey; // 分布式锁 key
private final long lockTimeout; // 锁超时时间(毫秒)
public DistributedListModifier(Jedis jedis, String listKey, long lockTimeout) {
this.jedis = jedis;
this.listKey = listKey;
this.lockKey = "lock:" + listKey;
this.lockTimeout = lockTimeout;
}
/**
* 向分布式 List 中添加元素(线程安全)
*/
public boolean addElement(T element) {
String lockValue = UUID.randomUUID().toString();
try {
// 1. 获取分布式锁
boolean locked = tryLock(lockValue);
if (!locked) {
return false; // 获取锁失败,返回重试
}
// 2. 序列化元素并添加到 Redis List
byte[] data = CollectionSerializer.serializeList(List.of(element), (Class<T>) element.getClass());
jedis.rpush(listKey.getBytes(), data);
return true;
} finally {
// 3. 释放锁
releaseLock(lockValue);
}
}
/**
* 获取分布式锁
*/
private boolean tryLock(String lockValue) {
String result = jedis.set(lockKey, lockValue, "NX", "PX", lockTimeout);
return "OK".equals(result);
}
/**
* 释放分布式锁(防止误释放)
*/
private void releaseLock(String lockValue) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
jedis.eval(script, List.of(lockKey), List.of(lockValue));
}
}5.3 集合传输优化技巧
- 分片传输:大数据量集合拆分后分批传输,避免单次传输过大导致超时
- 压缩传输:序列化后对数据进行压缩(如 GZIP),减少网络带宽占用
- 增量传输:仅传输新增/修改的元素,而非整个集合,降低传输开销
- 延迟加载:分布式场景中,先传输集合元数据(如大小、分片信息),按需加载具体数据
六、实战案例:基于集合的规则引擎设计
规则引擎是业务系统的核心组件,用于动态管理业务规则(如风控规则、促销规则),基于集合框架可实现轻量级规则引擎,支持规则的动态添加、匹配和执行。
6.1 需求分析
设计一个促销规则引擎,支持以下功能:
- 动态添加促销规则(如满减、折扣、赠品)
- 根据订单信息匹配符合条件的规则
- 执行规则并返回促销结果
- 支持规则优先级(高优先级规则先执行)
6.2 设计思路
- 规则接口(PromotionRule):定义规则的匹配条件和执行逻辑
- 规则引擎(RuleEngine):使用 TreeSet 存储规则(按优先级排序),提供规则添加、匹配、执行方法
- 订单上下文(OrderContext):封装订单信息,作为规则匹配和执行的入参
6.3 代码实现
6.3.1 订单上下文类(OrderContext.java)
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
/**
* 订单上下文:封装规则匹配所需的订单信息
*/
public class OrderContext {
private final String orderId;
private final BigDecimal totalAmount; // 订单总金额
private final List<String> productIds; // 商品 ID 列表
private final int memberLevel; // 会员等级
// 构造函数
public OrderContext(String orderId, BigDecimal totalAmount, List<String> productIds, int memberLevel) {
this.orderId = Objects.requireNonNull(orderId);
this.totalAmount = Objects.requireNonNull(totalAmount);
this.productIds = Objects.requireNonNull(productIds);
this.memberLevel = memberLevel;
}
// getter
public String getOrderId() {
return orderId;
}
public BigDecimal getTotalAmount() {
return totalAmount;
}
public List<String> getProductIds() {
return productIds;
}
public int getMemberLevel() {
return memberLevel;
}
}6.3.2 促销规则接口(PromotionRule.java)
/**
* 促销规则接口:所有规则需实现此接口
*/
public interface PromotionRule {
/**
* 规则优先级:数值越大,优先级越高
*/
int getPriority();
/**
* 规则匹配:判断订单是否满足规则条件
*/
boolean match(OrderContext context);
/**
* 执行规则:返回促销结果
*/
PromotionResult execute(OrderContext context);
/**
* 促销结果封装
*/
record PromotionResult(String ruleName, BigDecimal discountAmount, String gift) {}
}6.3.3 具体规则实现(满减规则、折扣规则)
import java.math.BigDecimal;
/**
* 满减规则:满 1000 减 200
*/
public class FullReduceRule implements PromotionRule {
@Override
public int getPriority() {
return 2; // 优先级:2
}
@Override
public boolean match(OrderContext context) {
// 订单金额 ≥1000 元
return context.getTotalAmount().compareTo(new BigDecimal("1000")) >= 0;
}
@Override
public PromotionResult execute(OrderContext context) {
return new PromotionResult("满1000减200", new BigDecimal("200"), "无");
}
}
/**
* 会员折扣规则:VIP 会员 9 折
*/
public class MemberDiscountRule implements PromotionRule {
@Override
public int getPriority() {
return 1; // 优先级:1(低于满减规则)
}
@Override
public boolean match(OrderContext context) {
// 会员等级 ≥3(VIP 会员)
return context.getMemberLevel() >= 3;
}
@Override
public PromotionResult execute(OrderContext context) {
BigDecimal discount = context.getTotalAmount().multiply(new BigDecimal("0.1"));
return new PromotionResult("VIP 9折", discount, "无");
}
}
/**
* 赠品规则:购买指定商品送赠品
*/
public class GiftRule implements PromotionRule {
private final String targetProductId;
private final String gift;
public GiftRule(String targetProductId, String gift) {
this.targetProductId = targetProductId;
this.gift = gift;
}
@Override
public int getPriority() {
return 3; // 优先级:3(最高)
}
@Override
public boolean match(OrderContext context) {
// 包含指定商品
return context.getProductIds().contains(targetProductId);
}
@Override
public PromotionResult execute(OrderContext context) {
return new PromotionResult("购买指定商品送赠品", BigDecimal.ZERO, gift);
}
}6.3.4 规则引擎类(RuleEngine.java)
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
/**
* 规则引擎:基于 TreeSet 按优先级管理规则
*/
public class RuleEngine {
// 存储规则:TreeSet 按优先级降序排序(优先级越高越先执行)
private final TreeSet<PromotionRule> rules = new TreeSet<>(Comparator.comparingInt(PromotionRule::getPriority).reversed());
/**
* 添加规则
*/
public void addRule(PromotionRule rule) {
rules.add(rule);
}
/**
* 匹配并执行规则:返回所有符合条件的规则结果
*/
public List<PromotionResult> executeRules(OrderContext context) {
List<PromotionResult> results = new ArrayList<>();
for (PromotionRule rule : rules) {
if (rule.match(context)) {
results.add(rule.execute(context));
// 若为排他规则,可在此处 break(本案例支持多规则叠加)
}
}
return results;
}
// 测试
public static void main(String[] args) {
// 1. 初始化规则引擎并添加规则
RuleEngine engine = new RuleEngine();
engine.addRule(new FullReduceRule());
engine.addRule(new MemberDiscountRule());
engine.addRule(new GiftRule("P001", "保温杯"));
// 2. 构造订单上下文(满 1000 元、VIP 会员、包含 P001 商品)
OrderContext context = new OrderContext(
"ORDER001",
new BigDecimal("1500"),
List.of("P001", "P002"),
3
);
// 3. 执行规则
List<PromotionResult> results = engine.executeRules(context);
// 4. 输出结果(按优先级排序:赠品规则 → 满减规则 → 折扣规则)
System.out.println("订单 " + context.getOrderId() + " 匹配的促销规则:");
for (PromotionResult result : results) {
System.out.printf("规则:%s,折扣金额:%s,赠品:%s%n",
result.ruleName(), result.discountAmount(), result.gift());
}
}
}6.4 测试结果与案例总结
6.4.1 测试输出
订单 ORDER001 匹配的促销规则:
规则:购买指定商品送赠品,折扣金额:0,赠品:保温杯
规则:满1000减200,折扣金额:200,赠品:无
规则:VIP 9折,折扣金额:150.00,赠品:无
6.4.2 案例总结
✅ 核心技术亮点:
- 集合选型:使用 TreeSet 存储规则,自动按优先级排序,无需手动维护顺序
- 接口抽象:定义 PromotionRule 接口,支持规则扩展(新增规则无需修改引擎代码)
- 灵活性:支持多规则叠加执行,可通过修改比较器或添加排他标记支持排他规则
- 可扩展性:规则可动态添加/删除,适用于业务规则频繁变化的场景
✅ 扩展方向:
- 规则持久化:将规则存储到数据库,支持动态配置和热更新
- 规则条件表达式:使用 EL 表达式或脚本语言(如 Groovy)定义规则条件,更灵活
- 规则执行监控:记录规则执行日志和结果,便于排查问题和优化规则
七、本章小结
本章聚焦 Java 集合框架的高级应用与架构设计,从缓存架构、设计模式融合、大数据量处理、分布式适配到业务组件设计,全面覆盖复杂场景的实践方案,核心要点回顾如下:
- 缓存架构:基于 LinkedHashMap 实现 LRU+TTL 本地缓存,结合分布式缓存设计多级缓存架构,兼顾性能和一致性。
- 设计模式融合:装饰器模式增强集合功能,享元模式复用重复对象,迭代器模式自定义遍历逻辑,提升代码扩展性。
- 大数据量处理:通过集合分片存储控制内存,结合线程池并行处理提升效率,分布式场景下可扩展为 MapReduce 架构。
- 分布式适配:优化集合序列化和传输效率,基于分布式锁保证数据一致性,适用于微服务和分布式系统。
- 业务组件设计:基于集合框架实现轻量级规则引擎,支持规则动态管理和灵活扩展,可复用至各类业务系统。
通过本章学习,读者应能跳出“基础 API 使用”的层面,站在架构设计的角度运用集合框架,解决高并发、大数据量、分布式等复杂场景的问题,设计出高性能、可扩展、易维护的 Java 应用。集合框架作为 Java 开发的基础工具,其灵活运用是高级开发工程师的核心能力之一,后续可结合具体业务场景持续深化实践。
到此这篇关于Java 集合框架高级应用与架构设计方案的文章就介绍到这了,更多相关Java 集合框架实战应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
