The counting sort that you implemented is definitely the way to go. I would clean up the code a little bit, though.
Boxing elem as an Integer, then unboxing it back to an int, is unjustified.
Writing a switch statement, rather than an else if chain, produces slightly cleaner bytecode.
You've mingled the output logic with the sorting logic, which is bad practice. You should define a separate function to do the output, especially since the main() is responsible for reading the input. The sorting function should be named to suggest that it only handles 0, 1, 2 as input.
Since you call Integer.parseInt() so much, you might be better off using a Scanner.
import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;
class GFG {
private GFG() {}
public static void sort123(int[] array) {
int count0 = 0, count1 = 0, count2 = 0;
for (int elem : array) {
switch (elem) {
case 0: count0++; break;
case 1: count1++; break;
case 2: count2++; break;
default: throw new IllegalArgumentException("Not 0, 1, or 2");
}
}
int i = 0;
while (count0-- > 0) { array[i++] = 0; }
while (count1-- > 0) { array[i++] = 1; }
while (count2-- > 0) { array[i++] = 2; }
}
public static String toString(int[] array) {
return Arrays.stream(array)
.mapToObj(String::valueOf)
.collect(Collectors.joining(" "));
}
public static void main (String[] args) {
Scanner scan = new Scanner(System.in);
int numTests = scan.nextInt(); scan.nextLine();
while (numTests-- > 0) {
int size = scan.nextInt(); scan.nextLine();
String[] inputs = scan.nextLine().split(" ");
int[] array = new int[size];
for (int j = 0; j < size; j++) {
array[j] = Integer.parseInt(inputs[j]);
}
sort123(array);
System.out.println(toString(array));
}
}
}