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
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?
No comments:
Post a Comment