Se o valor não é relevante, porque precisa dessa preocupação de um número gerar sempre o mesmo resultado? Trocar por qualquer valor aleatório não é suficiente? Caso não seja, não tem muito jeito. Ou vc faz algum cálculo, ou precisa manter algum controle para mapear os valores.
Usar o hashCode
do Integer
não vai adiantar, pois na implementação atual ele sempre retorna o próprio número.
O que daria pra fazer é sempre efetuar algum cálculo simples, como já sugerido acima com o operador %
. Mas se os dados são confidenciais, uma conta simples é fácil de adivinhar e portanto tem grandes chances de ser reversível.
Sem mais detalhes, posso sugerir uma solução simplista e “caseira”. Primeiro vc precisa ver quantos valores únicos existem (se for um banco de dados, um simples SELECT COUNT(DISTINCT valor) FROM tabela
te dá a resposta). Vamos supor que os valores sejam: 10, 20, 30, 40, 50, 10, 40 e 30. Ou seja, 8 valores, mas destes, temos apenas 5 valores únicos (10, 20, 30, 40 e 50).
Se não estão no banco de dados, dá pra saber a quantidade usando um Set
:
// verificar quais são os valores únicos
List<Integer> todosValores = Arrays.asList(10, 20, 30, 40, 50, 10, 40, 30);
Set<Integer> valoresUnicos = new HashSet<>(todosValores);
int qtdValoresUnicos = valoresUnicos.size(); // 5
Se a quantidade for pequena, daria para criar um Set
e ir adicionando números aleatórios, até que a quantidade seja atingida:
Set<Integer> valoresUnicos = // obtido anteriormente, ver código acima
int qtdValoresUnicos = // obtido anteriormente, ver código acima
Random rand = new Random();
Set<Integer> numeros = new HashSet<>();
while (numeros.size() < qtdValoresUnicos) {
// gera um valor entre 1000 e 100000
// a partir do Java 17, é assim
numeros.add(rand.nextInt(1000, 100000));
// antes do Java 17, é assim
//numeros.add(rand.nextInt(99000) + 1000);
}
// cria o mapeamento
Map<Integer, Integer> map = new HashMap<>();
Iterator<Integer> it = numeros.iterator();
for (Integer value : valoresUnicos) {
map.put(value, it.next());
}
E depois eu crio um Map
que mapeia cada valor para um número aleatório único (a unicidade foi garantida pelo Set
, que não permite valores duplicados). Assim, basta pegar o respectivo valor no Map
, por exemplo, map.get(10)
sempre retornará o mesmo número. E como este foi gerado aleatoriamente, não há como deduzir uma fórmula que permita o caminho inverso (desde que vc não guarde o Map
em nenhum lugar, claro).
Um detalhe é que este método não escala se tiver muitos valores possíveis. Imagine que a quantidade de valores únicos é 98 mil, e o Set
já está com 97.999 valores. Como no exemplo acima estou gerando números entre mil e 100 mil, há 99 mil possibilidades. A chance de sair algum número repetido é maior, o que quer dizer que o loop pode tentar várias vezes até sair algum que ainda não está no Set
.
Neste caso, uma alternativa é criar uma lista com todos os números, embaralhar e pegar a quantidade que precisa:
Set<Integer> valoresUnicos = // obtido anteriormente, ver código acima
int qtdValoresUnicos = // obtido anteriormente, ver código acima
// gera todos os números entre 1000 e 100000
List<Integer> numeros = new ArrayList<>();
for (int i = 1000; i < 100000; i++) {
numeros.add(i);
}
Collections.shuffle(numeros); // embaralha
// pega os primeiros (a quantidade é qtdValoresUnicos)
Iterator<Integer> it = numeros.subList(0, qtdValoresUnicos).iterator();
Map<Integer, Integer> map = new HashMap<>();
for (Integer value : valoresUnicos) {
map.put(value, it.next());
}
E pronto, o Map
gerado funciona da mesma forma.
E claro, vc pode ajustar o intervalo dos números aleatórios para a sua necessidade.
E como já disse, é uma solução bem caseira e simplista. A única garantia é que cada valor resulta em um outro valor único, e não permite volta. Claro, assumindo que o Map
será descartado logo em seguida. Ainda seria possível reproduzir os mesmos dados se for possível adivinhar o seed usado pela classe Random
, e aí vc poderia trocar por SecureRandom
, etc. Sem saber dos requisitos exatos, dá pra ficar especulando infinitamente sobre o que é “melhor” para este problema.
Se isso é o suficiente para o seu caso, não temos como saber só com as informações passadas. De qualquer forma, caso precise de algo mais robusto, aí o buraco é mais embaixo. Técnicas de anonimização de dados vão muito além da substituição simples: