Es una forma pero no es demasiado eficiente.
Estás sacando 30 números entre 0 y 29. Para hacerlo un poco más interesante vamos a hacerlo con 100.
Cuando sacas el primer número sale seguro, no ha salido antes. El segundo tiene 1 posibilidad entre 100 de ser repetido. Suponiendo que no lo es, lo sacamos. El tercero tiene 2 posibilidades entre 100 de ser repetido. Así vamos avanzando hasta que hacia el final, los números tienen cada vez más posibilidades de haber salido antes que de no haber salido.
El último número necesitará un montón de intentos hasta salir (sólo 1 entre 100 posibilidades de ser el que falta). Y sin embargo, ya sabemos cuál es, porque es el único que queda.
Y ahí está la clave. Dependiendo de las condiciones, hay algunos datos que nos permiten crear algoritmos mucho mejores.
En concreto, si hablamos de "números aleatorios que no se repiten" realmente ya no es una sucesión de números aleatorios. Lo que es, es una ordenación aleatoria de una serie de números.
Una serie de números aleatorios es potencialmente infinita y tiene que permitir (si no, no sería totalmente aleatoria) que haya repeticiones.
Mientras que una ordenación aleatoria lo que trata es que tenemos un conjunto determinado de números p.ej. [1,2,3,4,5,6,7,8,9,10] y queremos ordenarlos aleatoriamente.
No sé si es esto lo que quiere Ángel, pero si es eso, la forma de hacerlo es pensar así. Tenemos un array, y lo mezclamos aleatoriamente.
Un algoritmo típico es ir recorriéndolo y cambiando de sitio cada elemento con cualquier otro (incluyendo que se quede en su sitio). Algo como esto:
int[] numeros = new int[20]
int n = numeros.length;
for (int i = 0; i<n;i++) numeros[i] = i;
for (int i = 0; i<n-2; i++) {
// Tomamos al azar un indice entre i y el final
int j = i + (int)(Math.random()*(n-i));
// Intercambiamos numeros[i] y numeros[j]:
int temp = numeros[i];
numeros[i] = numeros[j];
numeros[j] = temp;
}
Si prefieres algo más simple podrías usar java.util.Arrays#sort(array,comparador) pasándole como comparador una función que genere números aleatorios. P.ej:
Integer[] numeros = new Integer[20];
int n = numeros.length;
for (int i = 0; i<n;i++) numeros[i] = new Integer(i+1);
Arrays.sort(numeros, new Comparator() {
public int compare(Object o1, Object o2) {
return ((int)(Math.random()*10) - 5);
}
});
Pero esta forma de hacerlo es bastante menos aleatoria que la anterior, los números tienden a estar más ordenados (los números bajos al principio y los altos al final).