cami-la / collections-java-api-2023

Este repositório é referente ao curso "Collection Framework API Java" e é uma valiosa contribuição para a comunidade de desenvolvedores Java, fornecendo exemplos práticos e recursos educacionais relacionados à poderosa API de coleções da linguagem Java.
https://web.dio.me/course/conhecendo-collections-java/learning/c5d6f4e1-6d05-4eea-93d8-d292c708999f
876 stars 636 forks source link

Exemplo de Generics Set #35

Closed EdilbertoMorais closed 10 months ago

EdilbertoMorais commented 10 months ago

Boa tarde @cami-la ,

segue abaixo o código utilizando o Set que você forneceu:

package main.java.generics;

import java.util.HashSet;
import java.util.Set;

public class GenericsExempleSet {
    public static void main(String[] args) {
        // Exemplo sem Generics
        Set conjuntoSemGenerics = new HashSet();
        conjuntoSemGenerics.add("Elemento 1");
        conjuntoSemGenerics.add(10); // Permite adicionar qualquer tipo de objeto

        // Exemplo com Generics
        Set<String> conjuntoGenerics = new HashSet<>();
        conjuntoGenerics.add("Elemento 1");
        conjuntoGenerics.add("Elemento 2");

        // Iterando sobre o conjunto com Generics
        for (String elemento : conjuntoGenerics) {
            System.out.println(elemento);
        }

        // Iterando sobre o conjunto sem Generics (necessário fazer cast)
        for (Object elemento : conjuntoSemGenerics) {
            String str = (String) elemento;
            System.out.println(str);
        }
    }
}

este código exibe um erro no IntelliJ:

image

Código que alterei para poder corrigir os erros:

package generics;

import java.util.HashSet;
import java.util.Set;
    public class GenericsExempleSet {
        public static void main(String[] args) {
            // Exemplo sem Generics
            Set<Object> conjuntoSemGenerics = new HashSet<>();
            conjuntoSemGenerics.add("Elemento 1");
            conjuntoSemGenerics.add(10); // Permite adicionar qualquer tipo de objeto

            // Exemplo com Generics
            Set<String> conjuntoGenerics = new HashSet<>();
            conjuntoGenerics.add("Elemento 1");
            conjuntoGenerics.add("Elemento 2");

            // Iterando sobre o conjunto de Generics do tipo String
            System.out.println("TIPO STRING");
            for (String elemento : conjuntoGenerics) {
                System.out.println(elemento);
            }

            System.out.println();

            // Iterando sobre o conjunto de Generics de qualquer tipo (sem uso de cast)
            System.out.println("TIPO GENÉRICO");
            for (Object elemento : conjuntoSemGenerics) {
                System.out.println(elemento);
            }
        }
    }

Poderia me informar o porque usando o código que você forneceu não roda diretamente sem estas alterações

cami-la commented 10 months ago

Oi, @EdilbertoMorais. Tudo certinho?

Então. quanto as "ondinas" que aparecem na IDE no exemplo abaixo, não significa erro não tá? Isso se chama warnings.

generics

No Java, a criação de coleções (como Listas, Set, Map...) que contenham tipos diferentes não é a prática recomendada, uma vez que as coleções em Java são projetadas para conter elementos do mesmo tipo.

A ocorrência da exceção java.lang.ClassCastException está correta, uma vez que esse é o comportamento esperado quando tentamos fazer um cast de um objeto para um tipo incompatível. Para lidar com essa exceção, podemos implementar o tratamento da Exception:

for (Object elemento : listaSemGenerics) {
    try {
        String str = (String) elemento;
        System.out.println(str);
    } catch (ClassCastException e) {
        System.out.println("Elemento não é uma String: " + elemento);
    }

Em vez disso, é mais apropriado usar Generics. A introdução de Generics tem o objetivo de solucionar precisamente esse tipo de situação. Quando se tenta criar uma Collection que pode conter tipos diversos, os Generics realizam uma verificação em tempo de compilação. Isso elimina a necessidade de efetuar Casts e de lidar com exceções eventualmente causadas por elementos diferentes dentro da Collection.

Repondi uma dúvida parecida com a sua nessa issue aqui: https://github.com/cami-la/collections-java-api-2023/issues/23#issuecomment-1712762444 Dá uma olhadinha, talvez esclareça ainda mais o entendimento. Mas se ainda continuar com dúvidas, vamos nos falando aqui. (:

EdilbertoMorais commented 10 months ago

Oi @cami-la, tudo certo graças a Deus.

Na verdade, a parte do erro que mencionei seria a da imagem do terminal do IntelliJ. Os warnings eu entendi que são alerta, na verdade, eu que me expressei de uma forma não tão clara, vendo o link que você mencionou, usando a sintaxe:

List listaSemGenerics = new ArrayList();

Quando rodo o programa assim que o for itera no elemento de tipo diferente, o erro no terminal ocorre. Porém, usando a sintaxe:

Set<Object> conjuntoSemGenerics = new HashSet<>();

Consigo iterar o for sem a necessidade do cast:

import java.util.HashSet;
import java.util.Set;
    public class GenericsExempleSet {
        public static void main(String[] args) {
            // Exemplo sem Generics
            Set<Object> conjuntoSemGenerics = new HashSet<>();
            conjuntoSemGenerics.add("Elemento 1");
            conjuntoSemGenerics.add(10); // Permite adicionar qualquer tipo de objeto

            System.out.println("TIPO GENÉRICO");
            for (Object elemento : conjuntoSemGenerics) {
                System.out.println(elemento);
            }
        }
    }

Dessa forma o programa roda e imprime ambos os tipos sem a necessidade de nenhuma tratativa de exception e/ou erro.

Minha dúvida agora é: Preciso colocar o "SET<Object>" para definir que ele será de qualquer tipo ou se eu deixar sem isso seria aplicado de forma padrão?

cami-la commented 10 months ago

Huuum, entendi. Deixa eu ver se consigo responder sua dúvida:

Percebe que ao declarar um Set<Object> e inicializá-lo com um HashSet<>, você está usando generics?

Assim, você permite que o conjunto contenha qualquer tipo de objeto, já que Object é a superclasse de todos os objetos em Java. Logo, você não precisa fazer casting ao adicionar elementos a esse conjunto.

Porém, essa prática Set<Object> conjuntoComGenericsContendoObject = new HashSet<>(); não é recomendada em muitos casos. Isso porque, ao usar Set<Object>, você perde a capacidade de aproveitar o benefício do tipo de segurança que os generics proporcionam. O objetivo dos generics é ajudar a detectar erros de tipo em tempo de compilação e fornecer um código mais seguro.

Ao usar Set<Object>, você está ignorando o propósito dos generics, tornando mais difícil para o compilador pegar erros de tipo em seu código.

No dia a dia, quando trabalhamos com coleções, fazemos da seguinte forma: Set<TipoEspecifico> conjunto = new HashSet<>();

Ficou melhor agora?

EdilbertoMorais commented 10 months ago

Percebe que ao declarar um Set e inicializá-lo com um HashSet<>, você está usando generics? Sim, essa parte aqui ficou claro, seria o mesmo que usar Set<String> o que define o tipo Strings para essa lista.

No dia a dia, quando trabalhamos com coleções, fazemos da seguinte forma: Set conjunto = new HashSet<>();

Agora ficou perfeito.

Essa, na verdade, era a minha dúvida. Como seria a forma correta de aplicar no dia a dia.