Print Twin Primes in Java
Problem
A twin prime pair is two prime numbers that differ by exactly 2 — listing them means finding every such pair within a range, not just checking one candidate pair.
Given an upper limit, list every twin prime pair found up to that limit.
Java Program
public class PrintTwinPrimes {
static boolean isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false; // found a divisor, not prime
}
return true;
}
public static void main(String[] args) {
int limit = 50;
StringBuilder result = new StringBuilder();
for (int i = 2; i <= limit - 2; i++) {
if (isPrime(i) && isPrime(i + 2)) { // both i and its neighbor two higher are prime
if (result.length() > 0) result.append(", ");
result.append("(").append(i).append(", ").append(i + 2).append(")");
}
}
System.out.println(result);
}
}Output
Core Logic
Trying every number up to the limit as the smaller half of a candidate pair, and checking whether it and its neighbor two higher are both prime, finds every twin prime pair in the range.
- 1
isPrime(n)is a helper method testing divisors only up to√n. - 2The loop tries every
ifrom2up tolimit - 2, soi + 2never runs past the limit. - 3
isPrime(i) && isPrime(i + 2)checks whether bothiand its neighbor two higher are prime. - 4Each matching pair is appended to the result as
(i, i + 2), separated by commas.
50, the scan finds six pairs, starting with (3, 5) and ending with (41, 43).Key Point: The loop only ever needs to reach limit - 2, not limit itself — checking i + 2 beyond the limit would either go out of range of interest or duplicate work already covered.
Why: Each of the n candidates triggers up to two O(√n) primality checks, and the result string can grow to hold every twin prime pair found.
Key Concepts
Approach 2: Java 8
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PrintTwinPrimesStream {
static boolean isPrime(int n) {
if (n < 2) return false;
return IntStream.rangeClosed(2, (int) Math.sqrt(n)).noneMatch(i -> n % i == 0);
}
public static void main(String[] args) {
int limit = 50;
// Keeps candidates where both i and i + 2 are prime, then formats each pair
String result = IntStream.rangeClosed(2, limit - 2)
.filter(i -> isPrime(i) && isPrime(i + 2))
.mapToObj(i -> "(" + i + ", " + (i + 2) + ")")
.collect(Collectors.joining(", "));
System.out.println(result);
}
}
Output
Core Logic
The same candidate check can filter a stream of numbers directly, then format and join the survivors.
- 1
IntStream.rangeClosed(2, limit - 2)generates every candidate for the smaller half of a pair. - 2
.filter(i -> isPrime(i) && isPrime(i + 2))keeps only the candidates where bothiandi + 2are prime. - 3
.mapToObj(i -> "(" + i + ", " + (i + 2) + ")")formats each surviving candidate into its pair notation. - 4
.collect(Collectors.joining(", "))joins all the formatted pairs into the final result.
Key Point: The filter condition is the exact same two-prime check the loop version uses — streams just change how the range is walked and the results collected.
Why: The stream still runs the same O(√n) primality checks per candidate, and Collectors.joining() builds a result string holding every matching pair.