1. 基础理论
先简单过下基础概念:
✅ 质数:只能被1和自身整除的自然数(大于1)
❌ 合数:非质数的自然数
⚠️ 特殊情况:数字1既不是质数也不是合数
本文将探讨在Java中判断质数的三种主流方案,各有适用场景。
2. 自定义实现方案
核心思路:检查2到该数平方根范围内是否存在能整除的数。
关键优化:只需检查到平方根即可,因为更大的因数必然对应更小的因数。
boolean isPrime(int number) {
return number > 1
&& IntStream.rangeClosed(2, (int) Math.sqrt(number))
.noneMatch(n -> (number % n == 0));
}
💡 踩坑提示:注意边界条件(number<=1时直接返回false)
3. 使用BigInteger类
当处理超大整数(超过64位)时,BigInteger的isProbablePrime()
是更优选择:
3.1 原理说明
- 返回
false
时100%是合数 - 返回
true
时是概率性质数(通过Miller-Rabin和Lucas-Lehmer算法) - 位数<100时仅用Miller-Rabin测试
- 确定性(certainty)参数控制检验强度
boolean isPrimeByBigInteger(int number) {
BigInteger bigInt = BigInteger.valueOf(number);
return bigInt.isProbablePrime(100); // 确定性参数100
}
⚠️ 注意:此方法适合大数场景,小数场景可能存在性能浪费
4. 使用Apache Commons Math
引入依赖后可直接调用现成API:
4.1 Maven依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
4.2 使用方法
Primes.isPrime(number); // 直接返回boolean结果
✅ 优势:代码简洁,经过充分测试
❌ 劣势:需要引入额外依赖
5. 批量查找数组中的质数
给定数组示例:
int[] theArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
5.1 使用Stream API实现
三种方案均可通过Stream管道优雅实现:
// 方案1:自定义实现
Set<Integer> result = Arrays.stream(theArray)
.filter(PrimeChecker::isPrime)
.boxed()
.collect(Collectors.toSet());
// 方案2:BigInteger实现
Set<Integer> resultByBigIntegerApproach = Arrays.stream(theArray)
.filter(PrimeChecker::isPrimeByBigInteger)
.boxed()
.collect(Collectors.toSet());
// 方案3:Apache Commons Math
Set<Integer> resultByApacheCommonsMath = Arrays.stream(theArray)
.filter(Primes::isPrime)
.boxed()
.collect(Collectors.toSet());
5.2 关键技巧
✅ **boxed()**:将IntStream
转为Stream<Integer>
以便收集到Set
✅ 方法引用:PrimeChecker::isPrime
使代码更简洁
✅ 链式调用:Stream API使逻辑一目了然
6. 方案对比总结
方案 | 适用场景 | 优势 | 缺点 |
---|---|---|---|
自定义实现 | 中小数字,无外部依赖 | 无需引入库,性能可控 | 大数场景效率低 |
BigInteger | 超大数字(>64位) | 概率性算法高效处理大数 | 小数场景性能浪费 |
Apache Commons Math | 快速开发,依赖允许 | 代码简洁,可靠性高 | 需要额外引入依赖 |
💡 经验建议:
- 常规数字用自定义实现
- 大数场景用BigInteger
- 项目已用Commons Math时直接调用其API
完整代码示例见:GitHub仓库