Excluding enums from Java generic method parameters - java

In Java, is it possible to specify a generic method that matches lists containing any objects except enums?
public class Foo {
public enum MyEnum {
ENUM_VALUE
}
public static <T ...generics magic...> void bar(List<T> argument) {
// .. code
}
public static void test() {
Foo.bar(Arrays.asList(new Object())); // OK
Foo.bar(Arrays.asList(new Exception())); // Still OK
Foo.bar(Arrays.asList(MyEnum.ENUM_VALUE)); // Compiler error, please?
}
}
I'm under the impression that Java generics does not support <T does not extend Something>-style syntax, but I'd like to be know for sure - and preferably be proven wrong :).
If I can't implement this limitation with generics, what is the best possible workaround? My current plan is below; is a better implementation possible?
public static <T> void bar(List<T> argument, Class<T> argumentType) {
if (Enum.class.isAssignableFrom(argumentType)) {
throw new IllegalArgumentException("Enums are disallowed.");
}
}
Edit: I'm interested in this because I have an API that allows the consumer to:
Pass in a List of T and specify whether to return references to the T's in the list or clones of the T's:
public <T> void setList(List<T> contents, boolean returnClones)
Retrieve the T's from the list:
public <T> T get(int index)
Of course, if T is an Enum, then specifying returnClones with true doesn't make sense - we can't create a clone of the Enum. There are also other cases where cloning doesn't work (e.g. a no-args constructor is not available). I'm trying to make the API as robust as possible.
Edit #2: I know Enums are immutable; I'm looking for the best way of preventing the caller from accidentally specifying invalid arguments to the API. The caller should never
Pass in a List<SomeEnumType> and specifying that clones should be returned. This doesn't make sense.
Pass in a List<SomeObjectWithoutNoArgsConstructor> and specifying that clones should be returned. This makes sense but is something we cannot support (it might be possible to clone the objects, but without a no-args constructor we don't know how).
Cloneable is a good suggestion, but the purpose of the interface is different: "A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class." (Cloneable JavaDoc). Since we're using Dozer for our cloning instead of calling clone() on the source object, I think Cloneable would unfortunately end up hurting more than helping in this case.

I did once a refactoring, where a long parameter changed to an Object. The solution was to do something like:
/**
* Not for enums.
* #param x use not an enum.
*/
#Deprecated
public <E extends Enum<E>> void f(E x) {
throw new IllegalArgumentException("...");
// Or better throw new UnsupportedOperationException("...");
}
public <T> void f(T x) {
...
}
With IDE support this will do nicely.
Best to mention in javadoc and exception message what to use instead, the other f or so.

Related

Workarounds to implement interface including <TIn extends T>, with X[] type parameter

Let's say we have some interface like this:
public interface Foo<T> {
<TIn extends T> void encode(TIn value)
T decode()
}
I'm using Foo a lot in my codebase, but I wish to add the TIn extends T to make it more flexible, to eg have a Foo<Map<X>> able to encode a HashMap<X> or a TreeMap<X>.
This works really well - until I tried to implement Foo<T[]>, where it seems to be impossible to implement, with public <TIn extends TItem[]> void encode(TIn array) giving a parse error "> expected" when it hits the brackets []. Even IntelliJ does nothing when it volunteers to implement the interface.
For what it's worth, if T is some other concrete final type (eg byte[], Boolean, etc), it seems that I can satisfy the interface by just returning T, so it seems to do some hidden intelligent fixing here. So it seems that it's just a problem with T[] where it can't detect T[] is final.
Does anyone have any ideas about how I can workaround this? I don't really care that TIn extends byte[] can only be met with TIn = byte[], I just want to implement the interface for the compiler to be happy; and so that this interface can be used elsewhere.
None of this makes sense. You don't need that TIn in the first place:
public interface Foo<T> {
void encode(T value);
T decode;
}
class Example {
void test() {
Foo<HashMap<String, Integer>> foo = null;
foo.encode(new HashMap<String, Integer>());
}
}
This compiles just fine. In general if you declare a new typevar that is used in only 1 place, it's pointless - typevars are solely a thing javac worries about, the runtime doesn't know what generics (typevars) are. Hence, it doesn't make much sense to use them unless they serve to link 2 different places where a type is mentioned, e.g. 'the type of parameter to the encode method, the return type of the decode() method? I don't care what it is, but, for any given usage of the Foo type, it's the same - that kind of 'linking').
Given that there's no need to introduce an additional type param on the encode method, there's no need to try to declare a new type var there.
The usual alternative to a typevar that is used in just a single location is ?. There is no functional difference between <F> void foo(List<F> in) and void foo(List<?> in).

Can I work with generic types from a calling class?

I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.
First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.
What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:
public interface CalledInterface<E> {
public E get() { ... }
public set(E e) { ... }
}
public class Called implements CalledInterface<String> {
...
}
Now what I want to do is:
public class Caller {
protected CalledInterface<?> c;
public Caller (CalledInterface<?> arg) {
c = arg;
}
public void run(){
// I can do this:
c.set(c.get());
// But I'd want to be able to do something like:
<?> element = c.get();
c.set(element);
}
}
What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?
First of all, keep in mind that generics is a compile time thing not a runtime.
Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:
String get();
void set(String e); //i assume you wanted to return void
So essentially this doesn't really make sense:
<?> element = c.get();
The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.
UPDATE
Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.
If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:
Object get();
void set(Object o);
This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).
If on the other hand you just change the c member (and the constructor argument of Caller) to:
CalledInterface<String> c;
Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.
After your edit:
// I can do this:
c.set(c.get());
No you can't. It won't compile with c being CalledInterface<?>. (Have you even tried it?)
To do this, you can use a "capture helper":
private static <T> void helper(CalledInterface<T> c) {
c.set(c.get());
}
public void run(){
helper(c);
}
Which also solves your second problem:
private static <T> void helper(CalledInterface<T> c) {
T element = c.get();
c.set(element);
}
public void run(){
helper(c);
}
There are a few minor mistakes in your code:
protected Called c;
public Caller (CalledInterface arg) {
c = arg;
}
You are not allowed to assign arg here, because the type CalledInterface is not a subtype of Called (it is the other way around)
Also you should give type information when using CalledInterface (it is allowed to leave it out, but only for legacy purposes).
Now to the part you are wondering about. For the type Called, the compiler knows get() returns a String, if you are not interested in that, you can of course always use Object as the type of element. The compiler also knows that set() takes a String as argument, so it requires you to give one. In generics is essentially the same as using Object in a case without generics (even though it isn't allowed on the location you use it, because it doesn't make sense). This means that you would be telling the compiler to forget the type on the first line (calling get()) and to unforget it on the line below.

Demand `T extends Comparable<T>` only for certain methods

I'm trying to write a generic class in Java. A few methods in that class require that T extends Comparable<T>. How can I make it such that T is required to be comparable only if one of those methods is used? Or maybe there's some other way I should organize my class?
Here's the class I'm trying to implement. Its and array that I plan to use on both comparable and non-comparable types.
// I know Java has its own containers, but this
// is homework and I'm not allowed to use them
class Array<T>
{
// Some methods that pose no
// special restrictions on T
// These require that T be comparable
public Array<T> union(...) {...}
public Array<T> intersect(...) {...}
}
You can hide type T for method. T of Test is not the same as T of CompareMethodhere.
public static class Test<T> {
<T extends Comparable<T>> void compareMethod(T t, Class<T> classt) {
}
void normalMethod(T t) {
}
}
Now example
Test<String> test = new Test<String>();//Comparable class
test.compareMethod("",String.class);//works fine
Test<Random> tes1t = new Test<Random>();//Non Comparable class
tes1t.compareMethod(new Random(),Random.class);//Compilation error here
tes1t.normalMethod(new Random());//Works fine
new Test<Random>().compareMethod("",String.class);// Not a good but can be valid
new Test<String>().compareMethod(new Random(),Random.class);//Compilation error here
Update:
After being cursed about this solution I did some search in java API and this practice gets followed for toArray() method
ArrayList<String> string = new ArrayList<String>();
string.toArray(new Integer[5]);<--Illegal however <T> is hide by toArray method
Edit: It looks like this is possible after all (see AmitD's post). But anyway, other possible solutions are
Refactor the methods requiring comparable into a subclass
Just use casts in the relevant methods, meaning that that part will only be checked at runtime.
It wont be possible through normal method such as using comparable.
It would be better if you share what is the exact requirement.
If Sorting in ArrayList/Arrays are your goal, then Comparing Non Comparable classes is useless. Sorting can only be done in objects of the same or sub types.
But if you are going to use compare for checking if the objects are equal or not then I'll suggest that you override equals(Object O) method.

Why can't parameter types be loosened in overridden methods?

This code is invalid:
interface Foo
{
public void foo(final String string);
}
public class Bar implements Foo
{
// Error: does not override.
#Override public void foo(final Object object)
{
}
}
Because every String is obviously an Object, I would expect this code to be perfectly fine: any code that depends on giving foo() a String would stil function when foo() actually takes an Object.
It appears, though, that method signatures have to be identical to those of the methods they're overriding. Why?
What if
interface Foo
{
void foo(String string);
void foo(Object string);
}
Then which method is overridden by Bar?
'loosening' as you put it should not impact on someone expecting to use your interface defined method in a particular way, as any methods you call on that object should in theory be callable on the specified object, but Eugene's point stands, becaause there would probably be a little compiler headache to deal with in determining what method you actually intended to override if you just vaguely want to stick to the interfaces specification. Also, why whould this be desireable if you are going to stick to moving up the inheritance heirarchy, because surelely you will be able to do all you want to the thing further down the hierarchy as to 'Object' for example? Possibly casting inside your method would solve your problem? If it is possible to do what you want to do, you will also probably start treading on the polymorphism paradigm.
I think this is a classical contravariance issue. Your interface requires a string to be passed as parameter, you want an implementation that accepts an object (because, after all, strings are also objects).
The problem is that if you allowed that, then you could no longer guarantee that the parameter being required by the interface is a string or any one of its ancestors. You might just as well pass any object to your implementation and you would be breaking the contract of the interface, putting in danger the type safety and type coherence of your design.
You do have options, though:
public class Bar implements Foo
{
#Override public void foo(final String object)
{
}
public void foo(final Object object)
{
foo((String) object);
}
}
By this, you would be ensuring that object is actually a string, making possible to the type system to check that you are actually complying with the interface contract established in the method signature.
Is there a particular scenario in which you would consider your contravariance example to be requirement?
It's just the constructs of the Java programming language. The structure of Java programs will grow on you. So for now just try and adjust.

If I need serializable should i use concrete List (e.g. ArrayList) or (Serializable)List?

We have a discussion in office and cannot understand which approach is better
I have a class (SomeClass) with some method which receives Serializable object. The signature is following:
public void someMethod(Serializable serializableObject){
...
}
And I need to call this method from another class, but I should provide it with some List as fact parameter. There are two different approaches
1. Serializable
private SomeClass someClass;
public void doSomething() {
List<String> al = new ArrayList<String>();
al.add("text");
someClass.someMethod((Serializable)al);
}
2. ArrayList
private SomeClass someClass;
public void doSomething() {
ArrayList<String> al = new ArrayList<String>();
al.add("text");
someClass.someMethod(al);
}
Benefit of the first example is that it adheres to the java’s best practices which says: use interface instead of concrete realization for reference type and any programmer while reading that source will understand that we don't need special behavior of the ArrayList. And the only place we need it's serializable behavior we are adding this behavior by casting it to the Serializable interface. And programmer can simply change this current realization of the List to some other serializable realization, for example, LinkedList, without any side affect on this element because we use interface List as it`s reference type.
Benefit of the second example is that we refer to ArrayList as to class which have not only List behavior but also Serializable behavior. So if someone looked at this code and tried to change ArrayList to List he would receive a compile time error which would reduce time for programmer to understand what is going on there
UPDATE: we can't change someMethod signature. It came from a third-party company and we use it not only for Serializable Lists but also for Strings, Integers and some other Serializable objects
You should use an interface when all you need is the methods an interface provides. (this is most cases) However, if you need more than one interface, you can use generics, but the simplest approach is to use the concrete type.
It's better to define ArrayList because this combines two interfaces - List + Serializable. You need both of them in one place.
It doesn't matter that much, but not that using interfaces should be applied more strictly for return types, and less strictly for local variables.
I would change the signature of the someMethod so that it reflects what it requires from the invoker of the method:
public class SomeClass {
public <T extends List<? extends Serializable> & Serializable> void someMethod(T t) {
}
public static void main(String[] args) {
SomeClass test = new SomeClass();
test.someMethod(new ArrayList<String>()); //Works
test.someMethod(new ArrayList<Image>()); //Compile time error, Image is not Serializable
List<String> l = null;
test.someMethod(l); //Compile time error
}
}
The signature of someMethod now says that you must invoke it with something that is a List, and that is Serializable, and contains elements that are Serializable
In this case, I would just use List, and not worry that the compiler cannot guarantee that your object is serializable (it most likely will be anyway, if you've done things right elsewhere).
Note that methods of the following type (which accept a Serializable parameter) provide a false sense of security, because the compiler can never guarantee that the entire object graph which needs to be serialized will actually be serializable.
public void write(Serializable s);
Consider an ArrayList (serializable) which contains non-serializable objects. The signature may as well just be:
public void write(Object o);
And then you don't have to worry about all the extraneous casting.
Also consider that, although you cannot change the signature of the API you are using, you can very easily create a wrapper API which has a different signature.
1 is generally the right thing to do. However in this case, my opinion would to be bend that and declare it as ArrayList<>. This avoids the cast and guarantees that someone can't change the implementation of the List to one that isn't Serializable.
You can't do (1) because you're not free to change the List implementation type arbitrarily, which is the whole idea of doing that. You can only use a List implementation that implements Serializable. So you may as well express that in the code.

Categories

Resources