Reputation: 21
I am having trouble trying to write a method to return the object that has the least volume in a generic ArrayList. These are the guidelines I was given to write the code:
min() - This method takes an ArrayList of Bounded Generic Type which only allows Shape objects and its subclasses. - The method should return the object with the minimum volume from the list of objects.
But I'm not entirely sure if I even followed it right. Is there a way I could use the Collections.min (and Collections.max since I have to write a max volume method too)? I get a bound mismatch error saying: The generic method min(Collection) of type Collections is not applicable for the arguments (ArrayList). The inferred type Shape is not a valid substitute for the bounded parameter >
My Shape class is simply an interface with a getVolume(); method where my other classes (Spheres, Ellipsoids, etc.) override this method:
public interface Shape {
public double getVolume();
}
And here is my min method (in another class with other methods) I'm having problems with:
public static <T> T min() {
ArrayList<? extends Shape> list;
T min = Collections.min(list));
return min;
Upvotes: 1
Views: 6791
Reputation: 1
public <E extends Comparable> E getMin(List<E> list){
E min = null;
for(E element:list){
if(min == null){
min = element;
continue;
}
if(element.compareTo(min) < 0){
min = element;
}
}
return min;
}
Upvotes: 0
Reputation: 73470
There are two options in java.utils.Collections
.
static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
The first of these requires your Shape to implement Comparator<Shape>
class Shape implements Comparable<Shape> {
int compareTo(Shape other) {
return Math.signum(getVolume()-other.getVolume);
}
...
}
ArrayList<Shape> myShapes = ...
Shape minShape = Collections.min(myShapes);
The second requires you to create a custom comparator:
class Shape {
...
}
class ShapeVolumeComparator implements Comparator<Shape> {
int compare(Shape s1, Shapes2) {
return Math.signum(s1.getVolume()-s2.getVolume());
}
}
ArrayList<Shape> myShapes = ...;
Shape minShape = Collections.min(myShapes, new ShapeVolumeComparator() );
The first is less code, but the second is more adaptable if you want to sort on something else - say surface area, or position.
Upvotes: 1
Reputation: 1319
You should this method http://www.tutorialspoint.com/java/util/collections_min_comparator.htm and provide a comparator :
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public abstract class Shape {
public abstract double getVolume();
public Shape min(Collection<? extends Shape> col) {
return Collections.min(col, new Comparator<Shape> () {
public int compare(Shape l, Shape r) {
return ((Double) l.getVolume()).compareTo(r.getVolume());
}
});
}
}
Upvotes: -1
Reputation: 6809
To compare the volumes, you can make Shape Comparable or use a Comparator.
This requires changes to all shapes, but none to the code using them. I used an abstract class to easily put the comparing to all classes.
public interface Shape extends Comparable<Shape> {
public double getVolume();
}
public abstract class BaseShape implements Shape {
public int compareTo(Shape other) {
return Double.compare(getVolume(), other.getVolume());
}
}
public class Box extends BaseShape {
public double getVolume() {
return volume;
}
}
public class Ball extends BaseShape { /* ... */ }
And to use:
Collections.min(collection);
This needs no modification to the shapes, but a bit more code to use them.
public class ShapeComparator implements Comparator<Shape> {
public int compare(Shape a, Shape b) {
return Double.compare(a.getVolume(), b.getVolume());
}
}
And to use:
Collections.min(collection, new ShapeComparator());
Upvotes: 1
Reputation: 304
It's because Java erases type at runtime, so the Collection doesn't know what type it's actually dealing with. It's a limiting factor when using Java generics - I've bumped heads with it before a few years ago but I couldn't figure out a way to get around it and it turned out to be a language restriction.
The best thing to do is create a public T getMinVolume(ArrayList<T> list)
method to iterate through each T.
eg.
public T getMinVolume(ArrayList<T> list) {
T min = null;
for(T item: list) {
if (min == null) {
min = item;
}
if (min > item) {
min = item;
}
}
return min;
}
Something like that, my Java is a bit rusty but the logic should work.
Upvotes: 1