Como eu faço pra inferir uma classe em Java. Tenho uma função que retorna uma lista, porém a classe que a List vai receber é definida dentro do método, porque pode ser mais de uma. Minha implementação abaixo funciona como eu esperava, mas eu preciso fazer um cast do chamador da função pra funcionar, e eu acho isso muito deselegante. Outra: se amanhã eu tiver outra classe no meu sistema que precise usar esse método, vou precisar adicioná-lo no IF, fazendo com que minha função seja 0% coesa.
public static List<?> obterListaDeObjetosBaseadoNaString(Class classe,
String... linhas) {
List<String> nomes = new ArrayList<>();
for (String linha : linhas) {
if (linha.contains(",")) {
String[] elementosDaLinhaSeparadaPorVirgula = linha.split(",");
for (String nome : elementosDaLinhaSeparadaPorVirgula) {
nomes.add(nome);
}
} else {
nomes.add(linha);
}
}
if (classe == Diretor.class) {
return nomes.stream()
.map(Diretor::new)
.collect(Collectors.toList());
} else {
return nomes.stream()
.map(Genero::new)
.collect(Collectors.toList());
}
}
Tendo em vista esse problema, alguém sabe como eu posso fazer pra deixar a inferência da classe de forma dinâmica?
Isso?
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
List<Integer> teste1 = obterListaDeObjetosBaseadoNaString(Integer.class, "1", "2", "3");
List<Double> teste2 = obterListaDeObjetosBaseadoNaString(Double.class, "1", "2", "3");
List<Custom> teste3 = obterListaDeObjetosBaseadoNaString(Custom.class, "1", "2", "3");
}
public static <T> List<T> obterListaDeObjetosBaseadoNaString(Class<T> classe, String ... linhas) {
return new ArrayList<T>();
}
static class Custom {
}
}
A “mágica” acontece por conta do <T>
definido no método.
Leia mais sobre aqui: https://docs.oracle.com/javase/tutorial/java/generics/methods.html
1 curtida
Cara, não peguei muito bem a ideia. Até deu certo aqui, mas ainda continuo com o mesmo código só que agora com um cast no próprio método.
public static <T> List<T> obterListaDeObjetosBaseadoNaString(Class<T> classe, String ... linhas) {
List<String> nomes = new ArrayList<>();
for (String linha : linhas) {
if (linha.contains(",")) {
String[] elementosDaLinhaSeparadaPorVirgula = linha.split(",");
for (String nome : elementosDaLinhaSeparadaPorVirgula) {
nomes.add(nome);
}
} else {
nomes.add(linha);
}
}
if (classe == Diretor.class) {
return (List<T>) nomes.stream()
.map(Diretor::new)
.collect(Collectors.toList());
} else {
return (List<T>) nomes.stream()
.map(Genero::new)
.collect(Collectors.toList());
}
}
Para evitar esses casts (e tb vários IF-ELSE), vc pode usar expressões lambda:
public static void main(String[] args) {
List<Diretor> diretores = obterListaDeObjetosBaseadoNaString(Diretor::new, "1", "2", "3");
List<Genero> generos = obterListaDeObjetosBaseadoNaString(Genero::new, "1", "2", "3");
}
public static <T> List<T> obterListaDeObjetosBaseadoNaString(Function<String, T> fn, String ... linhas) {
List<String> nomes = new ArrayList<>();
for (String linha : linhas) {
if (linha.contains(",")) {
String[] elementosDaLinhaSeparadaPorVirgula = linha.split(",");
for (String nome : elementosDaLinhaSeparadaPorVirgula) {
nomes.add(nome);
}
} else {
nomes.add(linha);
}
}
return nomes.stream().map(fn).collect(Collectors.toList());
}
Em vez de usar a expressão com ::new, poderia ser assim também:
List<Diretor> diretores = obterListaDeObjetosBaseadoNaString((v) -> new Diretor(v), "1", "2", "3");
List<Genero> generos = obterListaDeObjetosBaseadoNaString((v) -> new Genero(v), "1", "2", "3");
2 curtidas
Utilizando interface funcional ficou mais simples de entender o que está sendo feito. Obrigado pela ajuda.