Monday 25 July 2022

Extract the elements of specific type in a collection

 

Problem statement

I have a collection to store apples, bananas, oranges and mangoes. Write a program to extract specific type of fruits from the collection.

 

Approach 1:

We can solve this problem by isInstance() method of java.lang.Class.

 

Signature

public native boolean isInstance(Object obj);

 

isInstace method return true, if the object is an instance of given class, else false. This method is the dynamic equivalent of the Java language instanceof operator.

 

Fruit.java

package com.sample.app.interfaces;

public interface Fruit {
    
    public String aboutMe();

}

Apple.java

package com.sample.app.dto;

import com.sample.app.interfaces.Fruit;

public class Apple implements Fruit{

    @Override
    public String aboutMe() {
        return "I am Apple";
    }

}

Banana.java

package com.sample.app.dto;

import com.sample.app.interfaces.Fruit;

public class Banana implements Fruit{

    @Override
    public String aboutMe() {
        return "I am Banana";
    }

}

Orange.java

package com.sample.app.dto;

import com.sample.app.interfaces.Fruit;

public class Orange implements Fruit{

    @Override
    public String aboutMe() {
        return "I am Orange";
    }

}

Mango.java

package com.sample.app.dto;

import com.sample.app.interfaces.Fruit;

public class Mango implements Fruit{

    @Override
    public String aboutMe() {
        return "I am Mango";
    }

}

App.java

package com.sample.app;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.sample.app.dto.Apple;
import com.sample.app.dto.Banana;
import com.sample.app.dto.Mango;
import com.sample.app.dto.Orange;
import com.sample.app.interfaces.Fruit;

public class App {

    private static List<Fruit> filterFruits(List<Fruit> fruits, Class clazz) {

        return fruits
                .stream()
                .filter(obj -> clazz.isInstance(obj))
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList() {
            {
                this.add(new Apple());
                this.add(new Orange());
                this.add(new Banana());
                this.add(new Mango());
                this.add(new Apple());
                this.add(new Banana());
                this.add(new Orange());
            }
        };
        
        filterFruits(fruits, Apple.class).forEach(fruit -> System.out.println(fruit.aboutMe()));

    }
}

Output

I am Apple
I am Apple

Looks fine, but there is one specific behavior with isInstace method that we need to consider. ‘isInstance’ method returns true if the specified Object argument is an instance of the represented class or of any of its subclasses.

 

Let’s define GreenApple class.

 

GreenApple.java

package com.sample.app.dto;

public class GreenApple extends Apple{

    @Override
    public String aboutMe() {
        return "I am green apple";
    }
}

Let’s update the collection by adding GreenApple instances and try to extract only Apple objects.

 

App.java

package com.sample.app;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.sample.app.dto.Apple;
import com.sample.app.dto.Banana;
import com.sample.app.dto.GreenApple;
import com.sample.app.dto.Mango;
import com.sample.app.dto.Orange;
import com.sample.app.interfaces.Fruit;

public class App {

    private static List<Fruit> filterFruits(List<Fruit> fruits, Class clazz) {

        return fruits
                .stream()
                .filter(obj -> clazz.isInstance(obj))
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList() {
            {
                this.add(new Apple());
                this.add(new Orange());
                this.add(new Banana());
                this.add(new Mango());
                this.add(new Apple());
                this.add(new Banana());
                this.add(new Orange());
                
                this.add(new GreenApple());
                this.add(new GreenApple());
            }
        };
        
        filterFruits(fruits, Apple.class).forEach(fruit -> System.out.println(fruit.aboutMe()));

    }
}

Output

I am Apple
I am Apple
I am green apple
I am green apple

This approach is fine, if you want to extract all the elements of this type and sub types, but if you want to extract exact type matching elements (not the sub classes), then you can do class comparison.

 

Example

clazz.equals(obj.getClass())

 

Approach 2: Using Class.isAssignableFrom method.

 

Signature

public native boolean isAssignableFrom(Class<?> cls)

Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false

 

Just like isInstace method, this method also do not filter subclass objects.

 


 

App.java

package com.sample.app;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.sample.app.dto.Apple;
import com.sample.app.dto.Banana;
import com.sample.app.dto.GreenApple;
import com.sample.app.dto.Mango;
import com.sample.app.dto.Orange;
import com.sample.app.interfaces.Fruit;

public class App {

    private static List<Fruit> filterFruits(List<Fruit> fruits, Class clazz) {

        return fruits
                .stream()
                .filter(obj -> clazz.isAssignableFrom(obj.getClass()))
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList() {
            {
                this.add(new Apple());
                this.add(new Orange());
                this.add(new Banana());
                this.add(new Mango());
                this.add(new Apple());
                this.add(new Banana());
                this.add(new Orange());
                
                this.add(new GreenApple());
                this.add(new GreenApple());
            }
        };
        
        filterFruits(fruits, Apple.class).forEach(fruit -> System.out.println(fruit.aboutMe()));

    }
}

Output

I am Apple
I am Apple
I am green apple
I am green apple

Approach 3: Using class comparison of the object.

private static List<Fruit> filterFruits(List<Fruit> fruits, Class clazz) {

    return fruits
            .stream()
            .filter(obj -> clazz.equals(obj.getClass()))
            .collect(Collectors.toList());
}

Find the below working application.

 

App.java

package com.sample.app;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.sample.app.dto.Apple;
import com.sample.app.dto.Banana;
import com.sample.app.dto.GreenApple;
import com.sample.app.dto.Mango;
import com.sample.app.dto.Orange;
import com.sample.app.interfaces.Fruit;

public class App {

    private static List<Fruit> filterFruits(List<Fruit> fruits, Class clazz) {

        return fruits
                .stream()
                .filter(obj -> clazz.equals(obj.getClass()))
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<Fruit> fruits = new ArrayList() {
            {
                this.add(new Apple());
                this.add(new Orange());
                this.add(new Banana());
                this.add(new Mango());
                this.add(new Apple());
                this.add(new Banana());
                this.add(new Orange());
                
                this.add(new GreenApple());
                this.add(new GreenApple());
            }
        };
        
        filterFruits(fruits, Apple.class).forEach(fruit -> System.out.println(fruit.aboutMe()));

    }
}

Output

I am Apple
I am Apple

If you are interested in sub class objects too, then use either of approach1 and approach2, if you are interested only in given type of class (not the sub class objects), then use approach 3.









 

You may like

Interview Questions

How to check two double values for equality?

Why to do explicit type casting from double to float conversion?

When is a class or interface is initialized or loaded in Java?

How to check two float values equality?

How to check whether a class is loaded or not in Java?

How to get a random element from Set?

No comments:

Post a Comment