Just for fun, I asked chatGPT to give me a Java implementation of the sieve of Eratosthenes to find the first 100 prime numbers.
It gave me this:
public class SieveOfEratosthenes {
public static void main(String[] args) {
int n = 100; // Change this to the desired limit to find prime numbers up to n.
boolean[] isPrime = new boolean[n + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int p = 2; p * p <= n; p++) {
if (isPrime[p]) {
for (int i = p * p; i <= n; i += p) {
isPrime[i] = false;
}
}
}
System.out.println("Prime numbers up to " + n + ":");
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
System.out.print(i + " ");
}
}
}
}
So far so good. Now I asked for an implementation with lambdas. That pesky for loops are just too old.
public class SieveOfEratosthenesWithLambdas {
public static void main(String[] args) {
int n = 100; // Change this to the desired limit to find prime numbers up to n.
List<Integer> primes = IntStream.rangeClosed(2, n)
.boxed()
.filter(SieveOfEratosthenesWithLambdas::isPrime)
.collect(Collectors.toList());
System.out.println("Prime numbers up to " + n + ":");
primes.forEach(System.out::print);
}
static boolean isPrime(int number) {
return IntStream.rangeClosed(2, (int) Math.sqrt(number))
.allMatch(i -> number % i != 0);
}
}
Looks good. Compact and efficient.
Now it's when the fun starts. I ask for a "clean code" implementation, whatever that means. Here's the result:
public class SieveOfEratosthenesCleanCode {
public static void main(String[] args) {
int limit = 100; // Change this to the desired limit to find prime numbers up to 'limit'.
List<Integer> primes = findPrimesUpTo(limit);
System.out.println("Prime numbers up to " + limit + ":");
for (int prime : primes) {
System.out.print(prime + " ");
}
}
public static List<Integer> findPrimesUpTo(int limit) {
boolean[] isPrime = new boolean[limit + 1];
List<Integer> primes = new ArrayList<>();
// Initialize the array
for (int i = 2; i <= limit; i++) {
isPrime[i] = true;
}
// Sieve of Eratosthenes
for (int p = 2; p * p <= limit; p++) {
if (isPrime[p]) {
for (int i = p * p; i <= limit; i += p) {
isPrime[i] = false;
}
}
}
// Collect the prime numbers
for (int i = 2; i <= limit; i++) {
if (isPrime[i]) {
primes.add(i);
}
}
return primes;
}
}
I don't think it's "clean" enough. Methods are too large. I ask for a "cleaner" version:
public class PrimeNumberFinder {
public static void main(String[] args) {
int upperLimit = 100; // Change this to the desired limit to find prime numbers up to 'upperLimit'.
List<Integer> primeNumbers = findPrimeNumbers(upperLimit);
displayPrimeNumbers(primeNumbers);
}
public static List<Integer> findPrimeNumbers(int upperLimit) {
List<Integer> primeNumbers = new ArrayList<>();
boolean[] isComposite = new boolean[upperLimit + 1];
for (int number = 2; number * number <= upperLimit; number++) {
if (!isComposite[number]) {
for (int multiple = number * number; multiple <= upperLimit; multiple += number) {
isComposite[multiple] = true;
}
}
}
for (int number = 2; number <= upperLimit; number++) {
if (!isComposite[number]) {
primeNumbers.add(number);
}
}
return primeNumbers;
}
public static void displayPrimeNumbers(List<Integer> primeNumbers) {
System.out.println("Prime numbers found:");
for (int prime : primeNumbers) {
System.out.print(prime + " ");
}
System.out.println();
}
}
Methods are still too large. Refactor till you die.
public class PrimeNumberFinder {
public static void main(String[] args) {
int upperLimit = 100; // Change this to the desired limit to find prime numbers up to 'upperLimit'.
List<Integer> primeNumbers = findPrimeNumbers(upperLimit);
displayPrimeNumbers(primeNumbers);
}
public static List<Integer> findPrimeNumbers(int upperLimit) {
boolean[] isComposite = new boolean[upperLimit + 1];
sieveOfEratosthenes(isComposite, upperLimit);
return collectPrimes(isComposite);
}
private static void sieveOfEratosthenes(boolean[] isComposite, int upperLimit) {
for (int number = 2; number * number <= upperLimit; number++) {
if (!isComposite[number]) {
markMultiplesAsComposite(isComposite, number, upperLimit);
}
}
}
private static void markMultiplesAsComposite(boolean[] isComposite, int number, int upperLimit) {
for (int multiple = number * number; multiple <= upperLimit; multiple += number) {
isComposite[multiple] = true;
}
}
private static List<Integer> collectPrimes(boolean[] isComposite) {
List<Integer> primeNumbers = new ArrayList<>();
for (int number = 2; number < isComposite.length; number++) {
if (!isComposite[number]) {
primeNumbers.add(number);
}
}
return primeNumbers;
}
public static void displayPrimeNumbers(List<Integer> primeNumbers) {
System.out.println("Prime numbers found:");
for (int prime : primeNumbers) {
System.out.print(prime + " ");
}
System.out.println();
}
}
Well, that's it! A perfectly good algorithm has been "cleaned" until it is an incomprehensible garbage that needs much more cognitive load to understand than the original version.
Thanks Clean Code!
PS: the version in the book is even worse.
Top comments (0)