Java工具与算法实战:Arrays、Collections与JGraphT指南
Java工具与算法集成实战指南
一、工具类的高效应用
1. Arrays工具类实战
Arrays
类是Java中处理数组的瑞士军刀,提供多种静态方法简化数组操作。
排序与二分查找示例:
int[] scores = {85, 92, 78, 90, 65};
// 快速排序
Arrays.sort(scores); // [65, 78, 85, 90, 92]
// 二分查找(必须先排序)
int index = Arrays.binarySearch(scores, 90); // 返回3
// 并行排序(大数据量时更高效)
int[] largeArray = new int[1000000];
Arrays.parallelSort(largeArray);
实践建议:
- 对于基本类型数组,
Arrays.sort()
使用双轴快速排序(Dual-Pivot Quicksort) - 对象数组排序使用TimSort算法(稳定排序)
- 当数组大小超过
java.util.Arrays.MIN_ARRAY_SORT_GRAN
(默认8192)时,优先使用parallelSort()
2. Collections工具类妙用
Collections
类为集合操作提供了丰富的工具方法。
同步包装与不可变视图:
List<String> originalList = new ArrayList<>();
List<String> syncedList = Collections.synchronizedList(originalList);
// 不可变视图(Java 9+可用List.of更简洁)
List<String> immutableView = Collections.unmodifiableList(originalList);
// 单元素集合(比新建集合对象更高效)
Set<String> singleton = Collections.singleton("唯一值");
实践建议:
- 同步包装器通过在方法级别加
synchronized
实现线程安全 - 不可变视图是"浅不可变"——集合元素本身仍可修改
- Java 9+推荐使用
List.of()/Set.of()
创建真正不可变集合
二、算法与数据结构的集成
1. 图算法实战(JGraphT库)
引入依赖:
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>1.5.1</version>
</dependency>
最短路径算法示例:
Graph<String, DefaultWeightedEdge> graph =
new SimpleWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex("北京");
graph.addVertex("上海");
graph.addVertex("广州");
DefaultWeightedEdge edge1 = graph.addEdge("北京", "上海");
graph.setEdgeWeight(edge1, 1200); // 公里数
DefaultWeightedEdge edge2 = graph.addEdge("上海", "广州");
graph.setEdgeWeight(edge2, 1500);
// Dijkstra算法
DijkstraShortestPath<String, DefaultWeightedEdge> dijkstra =
new DijkstraShortestPath<>(graph);
GraphPath<String, DefaultWeightedEdge> path =
dijkstra.getPath("北京", "广州");
System.out.println("最短路径: " + path.getVertexList());
System.out.println("总距离: " + path.getWeight());
图可视化(mermaid示例):
实践建议:
- 对于无权图使用
SimpleGraph
,加权图使用SimpleWeightedGraph
常用算法:
- 连通性检测:
ConnectivityInspector
- 最小生成树:
KruskalMinimumSpanningTree
- 拓扑排序:
TopologicalOrderIterator
- 连通性检测:
2. Stream与数据结构交互
集合转Stream处理:
List<Employee> employees = ...;
// 统计薪资超过10000的人数
long count = employees.stream()
.filter(e -> e.getSalary() > 10000)
.count();
// 按部门分组
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// 并行流处理
double avgSalary = employees.parallelStream()
.mapToDouble(Employee::getSalary)
.average()
.orElse(0);
数组与Stream转换:
int[] numbers = {1, 2, 3, 4, 5};
// 数组转Stream
IntStream stream = Arrays.stream(numbers);
// Stream转数组
int[] newArray = stream.filter(n -> n % 2 == 0).toArray();
实践建议:
- 小数据集使用顺序流(stream()),大数据集使用并行流(parallelStream())
- 终端操作(如collect/count)会关闭流,不可重复使用
- 复杂操作可组合多个中间操作(filter/map/sorted等)
三、性能优化关键点
算法选择策略:
- 排序:小数组用快速排序,大数组用归并排序或并行排序
- 查找:已排序数组用二分查找(O(log n)),未排序用哈希表(O(1))
集合操作优化:
// 避免多次调用size() for (int i = 0, n = list.size(); i < n; i++) {...} // 预分配集合大小 List<String> largeList = new ArrayList<>(10000);
缓存友好性:
// 优先使用数组而非链表(更好的局部性) int[] matrix = new int[1000][1000]; // 连续内存块 // 按行优先顺序遍历二维数组 for (int row = 0; row < n; row++) { for (int col = 0; col < m; col++) { process(matrix[row][col]); } }
四、常见问题解决方案
Q1:如何选择集合与数组?
- 需要固定大小或基本类型时用数组
- 需要动态扩容和丰富API时用集合
Q2:Collections.synchronizedList与CopyOnWriteArrayList区别?
- 同步包装器:适合写多读少,全方法同步
- CopyOnWriteArrayList:适合读多写少,写时复制保证并发安全
Q3:Stream并行处理的适用场景?
- 数据量 > 1万条
- 无共享状态且操作独立
- 计算密集型而非IO密集型任务
通过合理运用Java工具类和算法库,可以显著提升开发效率和程序性能。建议根据具体场景选择最适合的数据结构和算法实现。