Java Generics error while compiling - java

Example
private static final Comparator<A> PRODUCT_CODE_COMPARATOR = new Comparator<A>()
{
#Override
public int compare(final A o1, final A o2)
{
return o1.getCode().compareTo(o2.getCode());
}
};
public static <T extends A> List<T> sortProductsByCode(final Collection<T> productModels)
{
return sortProducts(productModels, PRODUCT_CODE_COMPARATOR);
}
private static <T> List<T> sortProducts(final Collection<T> t, final Comparator<T> comparator)
{
final List<T> variants = new ArrayList<T>(t);
Collections.sort(variants, comparator);
return variants;
}
Getting an error at return sortProducts(productModels, PRODUCT_CODE_COMPARATOR);
Can anyone help?

You need your declaration of sortProducts to be:
private static <T> List<T> sortProducts(final Collection<T> t,
final Comparator<? super T> comparator)
This allows the Comparator to compare T's or any super class of T. Or, in other words, the method will accept Comparator<T> or Comparator<A>.

Related

Java Comparing Generics with Comparable<? super T> from another class

I have a "Schema" and "Field" model in which a Field represents a data type and has methods on how to parse it, and the schema is a collection of fields. I am trying to implement generic comparison, however, I can't get the code to compile and I can't figure out the proper generic scopes. How can I get this to work?
class Field<T extends Comparable<? super T>> {
T parse(String val) {
...
}
}
public class Schema {
Map<Integer, Field<?>> fields;
Field<?> getField(int index){ ... }
}
public class Comparison {
public static <T extends Comparable<? super T>> boolean greaterThan(Field<T> f, String val1, String val2) {
// compiles as expected
return f.parse(val1).compareTo(f.parse(val2)) > 0;
}
public static boolean greaterThan2(Field<?> f, String val1, String val2) {
// does not compile -> required capture of ? super capture of ?, provided capture of ?
return f.parse(val2).compareTo(f.parse(val2));
}
}
public class App {
public static void main(String[] args) {
Schema s = ...
// does not compile, required type Field<T>, provided type Field<capture of ?>
Comparison.greaterThan(s.getField(0), "val1", "val2");
// compiles
Comparison.greaterThan2(s.getField(0), "val1","val2");
}
}
Below code compiles in 1.8
import java.util.Map;
class Field<T extends Comparable<? super T>> {
T parse(String val) {
return null;
}
}
class Schema {
Map<Integer, Field<?>> fields;
Field<?> getField(int index){ return null; }
}
class Comparison {
public static <T extends Comparable<? super T>> boolean greaterThan(Field<T> f, String val1, String val2) {
// compiles as expected
return f.parse(val1).compareTo(f.parse(val2)) > 0;
}
}
public class App {
public static void main(String[] args) {
Schema s = new Schema();
//compiles ok
Comparison.greaterThan(s.getField(0), "val1", "val2");
}
}

How can I do <T super V>?

I have a method looks like this.
public static <E extends Enum<E> & FieldEnum<E, V>, V>
void fieldValues(class<E> enumType,
Collection<? super V> fieldValues) {
for ( enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
}
It might work.
List<Some> list = new ArrayList<>();
fieldValues(Some.class, list);
Now I want to change the method to return the given collection parameter(fieldValues). I did this.
public static <E extends Enum<E> & FieldEnum<E, V>, V, T super V>
Collection<T> fieldValues(Class<E> enumType,
Collection<T> fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
And the compiler complains.
com/github/.../lang/FieldEnums.java:[78,61] > expected
com/github/.../lang/FieldEnums.java:[78,62] illegal start of type
com/github/.../lang/FieldEnums.java:[78,69] '(' expected
How can I solve this? What is a proper way to return given collection so that I can do
List<Some> = fieldValues(Some.class, new ArrayList<Some>());
?
I found I just can
public static <E extends Enum<E> & FieldEnum<E, V>, V>
Collection<? super V> fieldValues(
Class<E> enumType, Collection<? super V> fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
Is there any other way better than this?
I'm answering for my own question so that anyone who has a similar problem can help themselves.
public static <E extends Enum<E> & FieldEnum<E, V>, V,
T extends Collection<? super V>>
T fieldValues(Class<E> enumType, T fieldValues) {
for (E enumConstant : enumType.getEnumConstants()) {
fieldValues.add(enumConstant.fieldValue());
}
return fieldValues;
}
Now I can do this.
List<Some> list = fieldValues(Some.class, new ArrayList<>());

Generic class as argument

I have a generic class Card . Rank is interface
class Card<T extends Enum<T> & Rank>
I am trying to create two static comparators of Card.
public final static Comparator<Card<?>> comparatorByAttribute1 = new Comparator<Card<?>>() {
#Override
public int compare(Card<?> o1, Card<?> o2)
{
...
}
};
How can I define that the type of o1 should be the same with o2 ?
Why not just use the actual type in the type declaration?
public final static Comparator<Card<ActualType>> comparatorByAttribute1 =
new Comparator<Card<ActualType>>() {
#Override
public int compare(Card<ActualType> o1, Card<ActualType> o2) {
return 0;
}
};
With...
public enum ActualType implements Rank {...}
Alternatively, if you want to keep the generic type <T>, you will need to resort to using a generic static method, because there is no way of having generic attributes in Java:
public final static <T extends Enum<T> & Rank> Comparator<Card<T>>
comparatorByAttribute1() {
return new Comparator<Card<T>>() {
#Override
public int compare(Card<T> o1, Card<T> o2) {
return 0;
}
};
}
Or, you resort to unsafe casting:
#SuppressWarnings({ "rawtypes", "unchecked" })
public final static <T extends Enum<T> & Rank> Comparator<Card<T>>
comparatorByAttribute1() {
// Your attribute
return (Comparator) comparatorByAttribute1;
}

JAVA and generic types issue

I'm facing an issue with generic types:
public static class Field<T> {
private Class<? extends T> clazz;
public Field(Class<? extends T> clazz) {
this.clazz = clazz;
}
}
public static void main(String[] args) {
// 1. (warning) Iterable is a raw type. References to generic type Iterable<T> should be parameterized.
new Field<Iterable>(List.class);
// 2. (error) The constructor Main.Field<Iterable<?>>(Class<List>) is undefined.
new Field<Iterable<?>>(List.class);
// 3. (error) *Simply unpossible*
new Field<Iterable<?>>(List<?>.class);
// 4. (warning) Type safety: Unchecked cast from Class<List> to Class<? extends Iterable<?>>.
new Field<Iterable<?>>((Class<? extends Iterable<?>>) List.class);
}
What's the best solution between the 1. and the 4. (or any other one by the way)?
public class Field <T> {
private Class <? extends T> clazz;
public <TT extends T> Field (Class <TT> clazz) {
this.clazz = clazz;
}
public static void main (String [] args) {
new Field <Iterable <?>> (List.class);
}
}

Using generics with collection of enum classes implementing same interface

I am trying to do reverse lookup on few enum classes implementing same Field interface by iterating through list of Classes using Guava's Maps.uniqueIndex:
Field valueOfSearchName = null;
for (final Class<? extends Enum<?>> clazz : ImmutableList.of(
EntityField.class,
AddressField.class,
PersonFunctionType.class)) {
valueOfSearchName = Fields.valueOfSearchName(clazz, term.field()); // error
if (valueOfSearchName != null) {
// do something...
break;
}
}
I don't want to repeat same code (for making index and doing lookup) in all enum classes, so I use helper static class Fields containing Fields.valueOfSearchName method:
public static <E extends Enum<E> & Field> Field valueOfSearchName(
final Class<E> clazz, final String searchName) {
// TODO: cache the index
final ImmutableMap<String, E> index = Maps.uniqueIndex(
EnumSet.allOf(clazz), GET_SEARCH_NAME_FUNCTION);
return index.get(searchName);
}
Unfortunately, Eclipse shows an error:
Bound mismatch:
The generic method valueOfSearchName(Class<E>, String) of type Fields is not
applicable for the arguments (Class<capture#1-of ? extends Enum<?>>, String).
The inferred type capture#1-of ? extends Enum<?> is not a valid substitute
for the bounded parameter <E extends Enum<E> & Field>
The problem is Class<? extends Enum<?>> clazz in for-each loop (not matching Field), but I don't know how to deal with this case (obviously I cannot add & Field to clazz).
Consider Class<? extends List<?>. Class<? extends List<?> has two wildcards whereas <E extends List<E>> Class<E> only has generic parameter. The former will admit Class<ArrayList<String>>. So without doing something extra special for enums, the types are not compatible.
How to fix? An extra layer of indirection!
public final class MetaEnum<E extends Enum<E>> {
private final E clazz;
public static <E extends Enum<E>> MetaEnum<E> of(E clazz) {
return clazz;
}
private MetaEnum(E clazz) {
this.clazz = clazz;
}
public E clazz() {
return clazz;
}
// ...
}
for (final MetaEnum<?> meta : ImmutableList.of(
MetaEnum.of(EntityField .class),
MetaEnum.of(AddressField .class),
MetaEnum.of(PersonFunctionType.class)
)) {
Field valueOfSearchName = Fields.valueOfSearchName(
meta.clazz(), term.field()
);
...
(Usual Stack Overflow dislaimer: Not so much as attempted to compile.)
Inspired by Tom Hawtin's answer I created wrapper class holding Classes, but only those with signature <E extends Enum<E> & Field>:
public final static class FieldEnumWrapper<E extends Enum<E> & Field> {
private final Class<E> clazz;
private final ImmutableMap<String, E> index;
public static <E extends Enum<E> & Field>
FieldEnumWrapper<E> of(final Class<E> clazz) {
return new FieldEnumWrapper<E>(clazz);
}
private FieldEnumWrapper(final Class<E> clazz) {
this.clazz = clazz;
this.index = Maps.uniqueIndex(
EnumSet.allOf(clazz), new Function<E, String>() {
#Override
public String apply(final E input) {
return input.searchName();
}
});
}
public Class<E> clazz() {
return clazz;
}
public Field valueOfSearchName(final String searchName) {
return index.get(searchName);
}
}
Now:
for (final FieldEnumWrapper<?> fieldEnum : ImmutableList.of(
FieldEnumWrapper.of(EntityField.class),
FieldEnumWrapper.of(AddressField.class),
FieldEnumWrapper.of(PersonFunctionType.class))) {
valueOfSearchName = fieldEnum.valueOfSearchName("POD_I_OS_PARTNER");
// ...
is type-safe and inappropriate usage of FieldEnumWrapper's static factory:
FieldEnumWrapper.of(NotEnumAndFieldClass.class)
generates compile error.
Moreover, valueOfSearchName is now method of FieldEnumWrapper what make more sense that helper class.
maybe something like this:
import java.util.*;
class N {
static int n;
}
interface HasField {
int getField();
}
enum Color implements HasField {
r, g, b;
public int getField() {
return field;
}
private int field = N.n++;
}
enum Day implements HasField {
m, t, w, th, f, sa, su;
public int getField() {
return field;
}
private int field = N.n++;
}
class Helper {
Helper(Set<HasField> set) {
for (HasField hasField : set)
if (hasField instanceof Enum) {
Enum<?> e = (Enum<?>) hasField;
for (Object o : e.getDeclaringClass().getEnumConstants()) {
map.put(((HasField) o).getField(), (Enum<?>) o);
}
} else
throw new RuntimeException(hasField + " is not an enum!");
}
final Map<Integer, Enum<?>> map = new TreeMap<Integer, Enum<?>>();
}
public class Main {
public static void main(String[] args) {
Set<HasField> set = new LinkedHashSet<HasField>();
set.add(Color.r);
set.add(Day.m);
Helper helper = new Helper(set);
for (int i = 0; i < N.n; i++)
System.out.println(i + " " + helper.map.get(i));
}
}

Categories

Resources