Don't print extras
You have
System.out.print(2 + ", ");
and
System.out.print(num + ", ");
Instead try
System.out.print(2);
and
System.out.print(", " + num);
and at the end
System.out.println(".");
Moving the comma before the current number works better as it is easier to treat the first result differently than the last result. Since the first result is known beforehand (2). Also, you only have to check if one result is first. You have to check all the results to see if they are last.
No even primes past 2
List<Integer> primes = new ArrayList<>();
if (n >= 1) {
primes.add(2);
System.out.print(2);
if (n >= 2) {
primes.add(3);
System.out.print(", " + 3);
}
}
int candidate = 1;
int interval = 2;
while (primes.size() < n) {
interval = 6 - interval;
candidate += interval;
for (int prime : primes) {
if (prime > candidate / prime) {
primes.add(candidate);
System.out.print(", " + candidate);
break;
}
if (candidate % prime == 0) {
break;
}
}
}
System.out.println(".");
This version keeps a list of what primes it has found. It initializes the list with 2 and 3 if it needs that many primes.
After that, it doesn't bother to check any even numbers and skips ever third odd number. This looks like
5, 7, 11, 13, 17, 19, 23, 25,...
Note that the odd numbers it skips (9, 15, 21, ...) are all divisible by three. It does this by alternating between adding 2 and 4 to get the next number. The increment
variable tracks whether the next one should add 2 or 4. Because \$6 - 2 = 4\$ and \$6 - 4 = 2\$, it alternates between them.
The primes
list keeps track of its own size, so we don't need a separate counter variable (i
in your original code).
I changed the names of num
and j
to candidate
and prime
in this case. I simply find candidate
to be more descriptive than num
. And of course this version only checks for prime
factors, so the name change from j
made sense.
The prime > candidate / prime
expression is checking if prime
is greater than the square root of candidate
. If so, we haven't found a factor smaller than or equal to the square root, so we know that candidate
is prime. The reason for using that form is that many implementations calculate both candidate / prime
and candidate % prime
at the same time. So this minimizes extra calculations.
Separate responsibilities
I left the mixing of calculations and output. That's generally bad style. You should move this into a method and return primes
. Then iterate over primes
to generate the output.
StringBuilder output = new StringBuilder();
for (int prime : generatePrimes(n)) {
output.append(prime);
output.append(", ");
}
output.setLength(output.length() - 2);
output.append('.');
System.out.println(output.toString());
This version will produce the same output as the corrected version of your original.
Or just use the join
version suggested by @ChatterOne.
System.out.println(String.join(", ", generatePrimes(n)) + ".");
Shorter and easier. Not as demonstrative of the powers of a StringBuilder
.