Producer and consumer with generics in Java

I have this method for retrieving objects that are instances of this class:

public class UtilitiesClass {

    public static final Collection<Animal> get(Collection<Animal> animals, Class<? extends Animal> clazz) {
        // returns the Animals which are an instanceof clazz in animals
    }
...
}

To call the method, I can do something like this:

Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);

This is good, but I would also like to be able to call the method in two ways:

Collection<Animal> dogs = UtilitiesClass.get(animals, Dog.class);

or

Collection<Dog> dogsTyped = UtilitiesClass.get(animals, Dog.class);

I mean, I want to save the result of the method in the Dog’s collection or in Animal, because Dog.classextendsAnimal.class

I thought something like this:

public static final <T> Collection<T> get(Class<T extends Animal> clazz) {
    // returns the Animals which are an instanceof clazz
}

But that will not work. Any hint?

Edit: Finally, using @Rohit Jain's answer, this is the solution when you call the UtilitiesClass method:

Collection<? extends Animal> dogsAnimals = UtilitiesClass.get(animals, Dog.class);
Collection<Dog> dogs = UtilitiesClass.get(animals, Dog.class);
+3
source share
3 answers

Yes, you have to make the method general. When declaring a type parameter, you must specify the boundaries:

public static final <T extends Animal> Collection<T> get(
                   Collection<Animal> animals, Class<T> clazz) {
}

, animal from animals Collection<T>, clazz. Class#isInstance(Object) , Class#cast(Object).

+5

Java 8 Class<T>, . , , :

public interface Animal {
    public void makeSound();
}

public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Waf");
    }
}

public class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Miauw");
    }
}

public abstract class Utils {
    @SuppressWarnings("unchecked")
    public static <T_IN, T_OUT> Collection<T_OUT> getBySubType(Collection<T_IN> input, Predicate<T_IN> predicate) {
        return input.stream()
                .filter(predicate)
                .map(element -> (T_OUT)element)
                .collect(Collectors.toList());
    }

    public static <T_IN, T_OUT> Collection<T_OUT> getBySubTypeSafe(Collection<T_IN> input, Predicate<T_IN> predicate, Function<T_IN, T_OUT> function) {
        return input.stream()
                .filter(predicate)
                .map(function)
                .collect(Collectors.toList());
    }
}

public class TestProject3 {
    private void init() {
        List<Animal> animals = new ArrayList<>();
        animals.add(new Dog());
        animals.add(new Cat());
        animals.add(new Dog());
        animals.add(new Cat());
        animals.forEach(Animal::makeSound);

        System.out.println();

        Collection<Dog> dogs = Utils.getBySubType(animals, animal -> (animal instanceof Dog));
        dogs.forEach(Animal::makeSound);

        System.out.println();

        Collection<Cat> cats = Utils.getBySubTypeSafe(animals, animal -> (animal instanceof Cat), animal -> (Cat)animal);
        cats.forEach(Animal::makeSound);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new TestProject3().init();
    }
}

:

Waf
Miauw
Waf
Miauw

Waf
Waf

Miauw
Miauw

, getBySubType resp getBySubTypeSafe:

  • Collection<T_IN>.
  • instanceof.
  • , T_OUT, Function<T_IN, T_OUT>, .
  • Collection<T_OUT>.
+2

The argument type must be a generic template for accepting input collections of any subclass of Animal.

public static final <T extends Animal> Collection<T> get(
        Collection<? extends Animal> animals, Class<T> clazz ) {
    Collection<T> filteredAnimals = new ArrayList<T>();
    for ( Animal animal : animals ) {
        if ( clazz.isInstance( animal ) ) {
            filteredAnimals.add( clazz.cast( animal ) );
        }
    }
    return filteredAnimals;
}
0
source

All Articles