Creating a new generic array that implements comparable - java

Is it possible to create a new generic array that implements comparable?
I have something like:
public class MyClass<T extends Comparable<T>> {
...
public T[] myAlgorithm( T[] list1, T[] list2 ) {
T[] newList = (T[]) new Object( ... );
if ( list1[0].compareTo( list2[0] ) < 0 ) {
...
}
return newList;
}
}
But it (obviously) throws the error:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable
I create a new instance of the Object class (the parent of all classes) and cast it to the parameterized type to get the parameterized array. I read from other sources that this is the way to do it. But I want it to use comparable in the way my algo shows in the code, and I don't want to use a collection.
Any way to do something like this?

One way would be as below (untested code):
public class MyClass<T extends Comparable<T>> {
public T[] myAlgorithm( T[] list1, T[] list2 ) {
#SuppressWarnings("unchecked")
T[] newList = (T[])Array.newInstance(list1[0].getClass(), list1.length);
for (T t1 : list1) {
for (T t2 : list2) {
if(t1.compareTo(t2)==0) {
//TODO
}
}
}
return newList;
}
}

Related

How to iterate over List<? extends E> in Java and use the actual object?

So I know that to iterate I can use either for-each or Iterator. But my problem is that I want to create a new list of the same type by removing some of the elements by a condition.
For ex-
List<? extends E> myList;
List<? extends E> newList = new ArrayList<>();
for(E element: myList) {
if(element.getName().equals("abc")) {
newList.add(element); // would throw an error because the list is of a different type.
}
}
How do I go about it? Is there any different way to tackle this?
You can try like that:
List<? extends E> newList = myList.stream().filter(x -> x.getName().equals("abc")).collect(Collectors.toList());
But if you need type that is hidden behind "?" then you will need to check inside your loop if element is an instance of certain class but it is not possible to add your element into List<? extends E>
So this will work:
public static void main(String[] args) {
List<? extends E> myList = new ArrayList<>();;
List<E> newList = new ArrayList<>();
for(E element: myList) {
if (element instanceof D) {
D elementD = (D)element;
if(elementD.getName().equals("abc")) {
newList.add(elementD); // would throw an error because the list is of a different type.
}
}
}
}
This also will work
public static void main(String[] args) {
List<? extends E> myList = new ArrayList<>();;
List<D> newList = new ArrayList<>();
for(E element: myList) {
if (element instanceof D) {
D elementD = (D)element;
if(elementD.getName().equals("abc")) {
newList.add(elementD); // would throw an error because the list is of a different type.
}
}
}
}
But this won't work:
public static void main(String[] args) {
List<? extends E> myList = new ArrayList<>();;
List<? extends E> newList = new ArrayList<>();
for(E element: myList) {
if (element instanceof D) {
D elementD = (D)element;
if(elementD.getName().equals("abc")) {
newList.add(elementD); // would throw an error because the list is of a different type.
}
}
}
}
You can't add any non-null values to a List<? extends E>, because the compiler can't verify that the type matches the unknown type.
You'd need to tell the compiler that the two lists are actually of the same type to allow that. You can do that by extracting the code to a separate method:
List<? extends E> myList;
List<? extends E> newList = filterList(myList);
...
private <T extends E> List<T> filterList(List<T> myList) {
List<T> newList = new ArrayList<>();
for(T element: myList) {
if(element.getName().equals("abc")) {
newList.add(element);
}
}
return newList;
}
This way you basically "name" the anonymous type ? extend E and call it T for the duration of the method call. Now the compiler knows that what you're doing is legit.
I did something like
mylist.removeIf(element -> element.getName().equals("abc"));

Method to take `T extends Iterable` and return T<E>?

How do I write a method that takes a parameter of some type T which is an instance of Iterable, as well as a parameter of Class<E>, and return T<E>?
public static <...> ... checkedCast(T iterable, Class<E> clazz) {
// Check elements and throw ClassCastException if invalid
#SupressWarning("checked")
... cast = (...)iterable;
return cast;
}
I want to use it like this:
// This should compile
ArrayList<?> a = ...;
ArrayList<String> b = checkedCast(a, String.class);
// So should this
HashSet<Number> c = ...;
Set<Integer> d = checkedCast(c, Integer.class);
// This shouldn't compile
b = checkedCast(a, Integer.class);
// This shouldn't compile
b = checkedCast(c, Integer.class);
// This should throw ClassCastException
checkedCast(a, Integer.class);
I know I can do this using overrides, but this requires me to write an override for every type:
public static <T> Iterable<T> checkedCast(Iterable<?> iterable, Class<T> clazz) {...}
public static <T> List<T> checkedCast(List<?> list, Class<T> clazz) {...}
public static <T> ArrayList<T> checkedCast(ArrayList<?> list, Class<T> clazz) {...}
public static <T> Set<T> checkedCast(Set<?> set, Class<T> clazz) {...}
One of the weaknesses of the Java type system's Generics extension is that how we think about types in the singular doesn't scale to how we think of types in the plural.
In short, Collections of a generic type cannot be safely cast, ever. Build a new list, pull out each type and check it individually, and the return the new list. If you disregard this warning, I'll direct someone to do something like
List<Customer> customers = new ArrayList<>();
customers.add(new Customer(...));
List<Object> customerObjects = checkCast(customers, Object.class);
customerObjects.add(new Order(...));
You have been warned.
See if this works for you. But, people can help you better if you can describe in more detail why you need such a method.
public static
<InputElement, OutputElement extends InputElement,
InputContainer extends Iterable<InputElement>,
OutputContainer extends Iterable<OutputElement>>
OutputContainer checkedCast(InputContainer iterable,
Class<OutputElement> clazz) {
#SuppressWarnings("unchecked")
OutputContainer output = (OutputContainer) iterable;
return output;
}
This works/matches your requirements - except for throwing a ClassCastException (if you really want that behaviour, you can include it in the checkedCast method yourself):
import java.util.*;
public class CheckedCast {
public static <GenB, GenA extends GenB, CollA extends List<GenA>> List<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (List<GenB>)iterable;
}
public static <GenB, GenA extends GenB, CollA extends Set<GenA>> Set<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (Set<GenB>)iterable;
}
static class One {}
static class Two extends One {}
static class Three {}
public static void main(String[] args) {
ArrayList<Two> test1 = new ArrayList<Two>();
List<One> test2 = checkedCast(test1, One.class);
// Shouldn't compile...
ArrayList<One> aa = checkedCast(test2, One.class); // output is ArrayList
List<Two> bb = checkedCast(test2, Three.class); // Three is not superClass of Two
ArrayList cc = checkedCast(new HashSet(), Integer.class); // Set cannot become List
ArrayList<One> dd = checkedCast(new LinkedList<One>(), One.class); // ArrayList is not superClass of List
}
}
Updated to match new requirement: ArrayList xs = checkedCast(new HashSet(), Integer.class) - shouldn't compile
Update: updated to assert returned Collection generic type extends input Collection's generic type.

using getter with java generic method argument

I have a method that takes a generic parameter type. The scenario I have is this method will be called with different parameter types.
class something{
public void someMethod(){
List<A> listA = ....; //Class A have a field String Id;
List<B> listB = ....; //Class B haave a field String Id;
testMethod(listA);
testMethod(listB);
}
private <T> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
}
In the above code all the parameters will be be a List<someObjectType>. All the object types have a common field and need to use the getter to fetch its value. Now since the method definition is generic, how do I achieve this?
Have A and B implement a common interface that has a method getID:
interface SomeInterface {
String getID();
}
then you could have:
private <T extends SomeInterface> void testMethod(List<T> list) {
for (T event : list) {
// now you can use `event.getID()` here
}
}
There is no point in creating such a generic method without bounded type. Since T isn't bounded to any type, you can't use specific interface on the objects inside the list. So if you want testMethod to get list of objects of any type, you should use List<?> instead.
This cannot be done. You can't handle two different lists with incompatible interfaces the same way in your method, unless you do something with instanceof, i.e.
public void testMethod(List<? extends Object> list) {
if(list.get(0) == null) return;
if(list.get(0) instanceof A) {
// Do the A stuff
} else {
// Do the B stuff
}
}
Define your method like this with T extending your common class/interface BaseType:
private <T extends BaseType> void testMethod( List<T> list ){
for( T event : list ){
//TODO (something like): event.getId();
}
}
Example:
public void someMethod() {
List<Integer> listA = Arrays.asList( new Integer[] {1, 4, 9} );
List<Double> listB = Arrays.asList( new Double[] {1.5, 4.2, 9.3} );;
testMethod(listA);
testMethod(listB);
}
private <T extends Number> void testMethod( List<T> list ){
for( T event : list ) {
// Note intValue() method is being called here which is provided
// in the base class Number that is being extended by T
System.out.println(event.intValue());
}
}
As other answers said, you need to bound the type parameter by some interface. But for what you're using it for, you don't actually need to have a T:
private void testMethod(List<? extends SomeInterface> list) {
for (SomeInterface event : list) {
// now you can use `event.getID()` here
}
}
I don't know if i really understand what you want.
But if you know, you will store for example Strings into your List and want to use the toUpperCase() method, how about just casting it?

Unchecked cast warning with Java Generics, type parameter, and returned list

This code is simplified as much as I can from a more complex class structure. In the real code, there were sub-types of the Integer and Double types I use here.
I'm trying to use Java Generics with a type parameter. If the user requests the type of Number.class, we want to combine the List<Integer> list and the List<Double> list into a single list.
While the code works, I cannot get ride of the unchecked cast warning (see the TODO tag). The warning is:
Type safety: Unchecked cast from List<Integer> to Collection<? extends T>
But, if I remove the cast, I get a compile error:
The method addAll(Collection<? extends T>) in the type List<T> is not applicable for the arguments (List<Integer>).
My code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class Generics1 {
static final List<Integer> intList = new ArrayList<Integer>(Arrays.asList(
1, 2, 3, 4));
static final List<Double> dblList = new ArrayList<Double>(Arrays.asList(
1.1, 2.2, 3.3));
public static <T extends Number> List<T> getObjects(Class<T> type) {
List<T> outList = new ArrayList<T>();
if (type == Number.class) {
// user asked for everything
// TODO: unchecked cast warnings here should be fixed
outList.addAll((Collection<? extends T>) intList);
outList.addAll((Collection<? extends T>) dblList);
} else {
// user asked for subtype of number
if (Integer.class.isAssignableFrom(type)) for (Integer i : intList)
if (type.isInstance(i)) {
T obj = type.cast(i);
outList.add(obj);
}
if (Double.class.isAssignableFrom(type)) for (Double d : dblList)
if (type.isInstance(d)) {
T obj = type.cast(d);
outList.add(obj);
}
}
return outList;
}
public static void main(String[] args) {
System.out.println("HI!");
System.out.println("integers: " + getObjects(Integer.class));
System.out.println("doubles: " + getObjects(Double.class));
System.out.println("numbers: " + getObjects(Number.class));
}
}
You could add this to your code:
#SuppressWarnings("unchecked")
Here is another SO post that explains "what" that means: What is SuppressWarnings ("unchecked") in Java?
And here is another one dealing with conversion of a link that may be useful: How do I fix "The expression of type List needs unchecked conversion...'?
Though with some recoding you could probably make the warning go away completely and not need to be suppressed.
(Class<T> type)
List<T> outList = new ArrayList<T>();
if (type == Number.class) {
// obviously, T==Number here, though the compiler doesn't know that
// so we do the cast. compiler will still warn. since the cast makes
// perfect sense and is obviously correct, we are ok with it.
List<Number> numList = (List<Number>)outList;
numList.addAll( intList);
numList.addAll( dblList);
} else {
The better solution, simply
for list in lists
for item in list
if item instance of type
add item to result
(previous answer deleted)
Here's a way of doing this with Guava:
#SuppressWarnings("unchecked")
public static <T> List<T> filterAndCollapse(final Class<T> type,
Collection<?> a, Collection<?> b) {
List combined = new ArrayList();
Predicate<Object> filter = new Predicate<Object>() {
public boolean apply(Object obj) {
return type.isInstance(obj);
}
};
combined.addAll(Collections2.filter(a, filter));
combined.addAll(Collections2.filter(b, filter));
return combined;
}
// ...
filter(Number.class, intList, dblList);
Edit: The fully-type safe way for comparison.
public static <T> List<T> filterAndCollapse(final Class<T> type,
Collection<?> a, Collection<?> b) {
List<T> combined = new ArrayList<T>();
Predicate<Object> filter = new Predicate<Object>() {
public boolean apply(Object obj) {
return type.isInstance(obj);
}
};
Function<Object, T> transform = new Function<Object, T>() {
public T apply(Object obj) {
return type.cast(obj);
}
};
combined.addAll(Collections2.transform(Collections2.filter(a, filter),
transform));
combined.addAll(Collections2.transform(Collections2.filter(b, filter),
transform));
return combined;
}
Unfortunately there's no way to filter and transform in one step with Guava, to my knowledge.

Generic instance variable in non-generic class

I'm trying to write a class that has a generic member variable but is not, itself, generic. Specifically, I want to say that I have an List of values of "some type that implements comparable to itself", so that I can call sort on that list... I hope that makes sense.
The end result of what I'm trying to do is to create a class such that I can create an instance of said class with an array of (any given type) and have it generate a string representation for that list. In the real code, I also pass in the class of the types I'm passing in:
String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);
Originally I didn't even want to pass in the class, I just wanted to pass in the values and have the code examine the resulting array to pick out the class of the values... but that was giving me troubles too.
The following is the code I have, but I can't come up with the right mojo to put for the variable type.
public class MyClass {
// This doesn't work as T isn't defined
final List<T extends Comparable<? super T>> values;
public <T extends Comparable<? super T>> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on variable declaration line:
Syntax error on token "extends", , expected
Any help would be very much appreciated.
Edit: updated code to use List instead of array, because I'm not sure it can be done with arrays.
#Mark: From everything I've read, I really want to say "T is a type that is comparable to itself", not just "T is a type that is comparable". That being said, the following code doesn't work either:
public class MyClass {
// This doesn't work
final List<? extends Comparable> values;
public <T extends Comparable> MyClass (T... values) {
this.values = new ArrayList<T>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable> List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}
error on add line:
The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)
error on sort line:
Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>
Conclusion:
What it comes down to, it appears, is that Java can't quite handle what I want to do. The problem is because what I'm trying to say is:
I want a list of items that are
comparable against themselves, and I
create the whole list at once from the
data passed in at creation.
However, Java sees that I have that list and can't nail down that all the information for my situation is available at compile time, since I could try to add things to the list later and, due to type erasure, it can't guarantee that safety. It's not really possible to communicate to Java the conditions involved in my situation without applying the generic type to the class.
I think that the simple answer is that you cannot do that. If the type of one of a classes attributes depends on a type parameter, that parameter has to be declared at the class level. And I don't think that it "makes sense" any other way.
If T in your example is not a type parameter of the class, what is it? It cannot be the type parameter of the method, because that type is determined by how the method is called. (If the method is called in different static contexts with different inferred types for T, what is the notional type of T in the context of the attribute declaration?)
So to bring this back to what you are trying to do here, an instance of MyClass will hold elements of some type, and you want to be able to insert and remove elements in a statically typesafe fashion. But at the same time you don't want to be able to say what that type is. So how is the compiler supposed to statically distinguish between a MyClass instance that holds (say) Integer objects and one that holds String objects?
I don't even think you could implement this with explicit dynamic typechecks. (I think that type erasure means that the implementation of the getSortedList() method cannot find out what actual type is bound to its return type.)
No. The real solution is to make MyClass a generic class that declares the type parameter T; e.g.
public class MyClass <T extends Comparable<T>> {
and remove the declaration of the method-level type parameter T from the two methods.
There's plenty of unchecked warnings in this, but in principle it's not necessary to keep the List as anything but something containing things you know are Comparable. You enforce the rules you need to in the constructor, and everything else should be fine. How about something like this:
public class MyClass {
final private List<Comparable> values;
public <T extends Comparable<? super T>>MyClass(T... values){
this.values = new ArrayList<Comparable>();
for(T item : values) {
this.values.add(item);
}
}
public <T extends Comparable<? super T>> List<T> getSortedLst() {
Collections.sort(this.values);
return (List<T>)this.values;
}
}
A quick test using the following shows that for classes that implement Comparable (like Integer and String) MyClass behaves as expected, but will throw a compilation error for classes that do not implement Comparable:
class Junk { }
public static void main(String[] args){
MyClass s = new MyClass(1,2,3);
System.out.println(s.getSortedLst());
MyClass a = new MyClass("c", "a", "b");
System.out.println(a.getSortedLst());
MyClass c = new MyClass(new Junk());
}
I believe the following will achieve what you want (stronger typing of Comparable). This will prevent people adding Comparable objects which are not from your interface to the list and allow multiple implementations.
public class test<T extends ComparableType> {
final List<T> values = new ArrayList<T>();
public test (T... values) {
for(T item : values) {
this.values.add(item);
}
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
public interface ComparableType extends Comparable<ComparableType> {}
public class ConcreteComparableA implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
public class ConcreteComparableB implements ComparableType {
#Override
public int compareTo(ComparableType o) {
return 0;
}
}
edit:
I know this may be obvious; but if you do not wish the class to be Generic this solution will also work with:
public class test {
final List<ComparableType> values = new ArrayList<ComparableType>();
public test (ComparableType... values) {
for(ComparableType item : values) {
this.values.add(item);
}
}
public List<ComparableType> getSortedLst() {
Collections.sort(this.values);
return Collections.unmodifiableList(this.values);
}
}
Consider it like this (what I am about to say isn't reality. but it illustrates why you need to do what you need to do):
class Foo<T>
{
private T value;
T getValue() { return value; }
void setValue(T val) {value = val; }
}
// some code that uses the above class
Foo<Integer> iFoo = new Foo<Integer>();
Foo<String> sFoo = new Foo<String>();
iFoo.setValue(5);
sFoo.setValue("Hello");
When this happens the compiler (DOES NOT REALLY DO WHAT I AM ABOUT TO SAY!) generates the following code:
class IntegerFoo
{
private Integer value;
Integer getValue() { return value; }
void setValue(Integer val) {value = val; }
}
class StringFoo
{
private String value;
String getValue() { return value; }
void setValue(String val) {value = val; }
}
// some code that uses the above class
IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");
If you were able to have the instance variables/methods parameterized without parameterizing the class the above thing (WHICH IS NOT REALITY!) wouldn't work.
What you are trying to do should be possible with static methods, but I don't think that is what you want.
Can you explain why you want to do the code you are trying to do? Perhaps we can figure out a better way to do what you want to do that works within the language.
I'd do it this way (I did it as a list or as an array), unless you really need the instance variable/methods:
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyClass
{
public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
{
final List<T> temp;
temp = new ArrayList<T>(vals.length);
temp.addAll(Arrays.asList(vals));
Collections.sort(temp);
return (Collections.unmodifiableList(temp));
}
public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
final T ... vals)
{
final T[] temp;
temp = (T[])Array.newInstance(clazz,
vals.length);
System.arraycopy(vals,
0,
temp,
0,
vals.length);
Arrays.sort(temp);
return (temp);
}
public static void main(final String[] argv)
{
final List<String> list;
final String[] array;
list = MyClass2.asSortedList("c", "a", "b");
System.out.println(list);
array = MyClass2.asSortedArray(String.class, "z", "y", "x");
System.out.println(Arrays.deepToString(array));
}
}
the type constraint you want on the variable can't be expressed directly. you can introduce a new type to bridge the problem.
static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}
final MyList<?> values;
however, there is no point to be extremely type safe in a private piece of code. Generic is there to help you clarify your types, not to obfuscate them.
public class MyClass<T extends Comparable<? super T>> {
// This doesn't work as T isn't defined
final List<T> values;
public MyClass (T... values) {
this.values = new ArrayList<T>(Arrays.asList(values));
}
public List<T> getSortedLst() {
Collections.sort(this.values);
return this.values;
}
}

Categories