Better way to deal with java generics handling? - java

Have a metod:
public <T> T foo(Class<T> type);
When I call it like:
String s = foo(String.class);
everything is fine. This also works:
Set s = foo(Set.class);
However, the following does not compile:
Set<String> s = foo(Set.class); // compilation error
so I fix it with something stupid like:
Set<?> tmp = foo(Set.class);
Set<String> s = (Set<String>) tmp;
I can't change the signature of foo(). Is there better way to make this assignment that I am missing?
EDIT
For some strange reason, it is not clear what I am doing here. So, method foo here is a method that takes some input plus Class<T>. It than takes the input and creates an instance of given class. So, the real signature of foo may be:
public <T> T parseStringToClass(String input, Class<T> targetClass);
And the usage may be:
Integer value = parseStringToClass("123", Integer.class);
There is nothing unusual here - it's fairly common signature for any parser and converter out there.

You're not going to get any help from the compiler, if that's what you're looking for. As has been observed in comments, generics don't work the way you want them to.
The best you can do is combine your cast with your invocation of foo():
#SuppressWarnings("unchecked") // Added to keep my Eclipse happy
Set<String> s = (Set<String>) parseStringToClass("Set<String>, Hello World, Goodnight Irene", Set.class);
This of course relies on the ability of parseStringToClass to recognize that it's being handed a String that has multiple Strings inside it, and that they should be converted into a Set, itself a nontrivial task.
You'll no doubt observe that the compiler doesn't have any idea whether the Set being returned is a Set<String>. That information just isn't available.

Since java's generics are erased, List<String> and List<Object> are both represented by one class: List. If you really need to represent an instantiated generic type at runtime you can use Guava's TypeToken to do so, but this has quite a bit of overhead and is not always as useful as you might think.
Ultimately it depends on what the foo method does on how to solve this in the most elegant way.

According to the link below, you can't get the literal for the generic type
http://goo.gl/6CtqGt
What I'd suggest you to do if you really need to use one method is:
Set<String> set = foo(new HashSet<String>().getClass());
It's very ugly but it works.

Related

Why does Java stack Optionals?

I'm generally very happy with the design of the Java language but today I came across a strange design choice.
I don't know any platform where you can suggest changes to the Java language for version 9 or 10 and therefore I'm writing this issue here.
With Optionals you have a much better control over the behaviour if a value is null.
Today I mapped a value in a stream to an Optional.
I was really surprised, that findFirst then gives me a Optional<Optional<T>> instead of just Optional<T>.
Where is the point in having Optional<Optional<T>>?
For Java 9 and Streams this is solved with .flatMap(Optional::stream) but this is only a work around and boilerplate code.
Wouldn't it be much better if Optionals generally wouldn't stack and always flats down?
Optional<Optional<T>> => Optional<T>
Optional.of(Optional.of("")) => Optional.of("")
Further explanation:
Working with Optionals you don't care if the sub optional was null or if the actual object was null. It always would come down to Optional.empty().
String s = null;
Optional<String> opt = null;
Optional.of(s) => Optional.empty()
Optional.of(opt) => Optional.empty()
Also if you are working with optionals you are only interested in the object. So if you try to get the object you always have to double get and check the optional.
if(optionalOfOptional.isPresent()) {
optional = optionalOfOptional.get();
if(optional.isPresent()) {
objectOfInterest = optional.get();
}
}
I even see this being a source for errors since you would always need to check both optionals if you condition on your object being present.
if(optionalOfOptional.isPresent() && optionalOfOptional.get().isPresent()) {
...
}
Only checking the first optional could easily lead to mistakes.
In addition, why would it make sense to have a Optional that is null in the first place? Isn't optional there to get rid of working with null?
On the method level this could be solved for sure.
For example Optional.of could look something like:
public static <T> Optional<T> of(T value) {
return value instanceof Optional ? value : new Optional<>(value);
}
On the type level this is probably not that easy.
It simply doesn't make sense to forbid Optional<Optional<T>>.
Let's say you've got a List<Optional<T>>. The following lists are different:
List<Optional<T>> listA = Arrays.asList(Optional.empty());
List<Optional<T>> listB = Arrays.asList();
They're obviously different: the first is non-empty, the second is empty.
Correspondingly, the result of invoking findFirst() on their streams is different:
System.out.println(listA.stream().findFirst().isPresent()); // true
System.out.println(listB.stream().findFirst().isPresent()); // false
Now, I know about the meaning of the data in those lists that Java can't possibly know. Let's say that the lists contain the results of invoking a list of Callable<Optional<T>>s. In that case, there might be an important difference to my application between:
I invoked N>0 callables, and all of them returned Optional.empty()
I invoked zero callables.
So I really don't want the language or API to assume that there's no difference between the two, and converting the Optional<Optional<T>> to an Optional<T>.
And since a List<E>.stream().findFirst() always returns an Optional<E>, there's no way to prevent an Optional<Optional<T>> without preventing me creating a List<Optional<T>> (or Collection, Set, HashMap<K, Optional<T>> etc). So, you'd basically have to completely disallow nested generics, which would be a major loss of functionality.
I'm quite contented with the existence of Optional<Optional<T>>, as it is entirely consistent with the rest of the language. If you don't like them, just avoid creating them; but don't think that's right for everybody else.
I talk about this elsewhere that an Optional<T> should never be null. It violates what Optional<T> promises: getting rid of NullPointerExceptions.
Therefore, I think it is a deficient design in the Optional API to allow Optional<Optional<T>>. The methods to get instances of Optional should behave better when given an Optional. But that being said, they can't. They could be accomplished if Optional.of was overloaded except for one slight issue.
Since you can have a generic type T that is of type Optional, you can't have two Optional.of methods (one for Optional and one for T). Occasionally it would prevent some code from compiling if someone had the bright idea to have an Optional<Optional<T>>. Take the below code, it will fail to compile.
package otherCode;
public class Abc<T> {
public static void main(String[] args) {
Abc<B> test1 = new Abc<>();
test1.foo(new A());
test1.foo(new B());
Abc<Base> test2 = new Abc<>();
test2.foo(new A());
test2.foo(new B());
Abc<A> test3 = new Abc<>();
// these two don't compile
test3.foo(new A());
test3.foo(new B());
}
public void foo(A item) {
System.out.println("Foo");
}
public void foo(T item) {
System.out.println("bar");
}
public static class Base {
}
public static class A extends Base {
}
public static class B extends Base {
}
}
Without forcing a language and syntax change on the entire language (forbidding a Optional<Optional<T>>) the automatic conversion is not an easy task.
Java 8 in general I found took developers a while to grasp. When it first came out, I'd see Map<String, Optional<T>> when Map<String, T> would have sufficed or I did see Optional<Optional<T>>. I even saw Map<Optional<T>, Optional<Set<Optional<T>>>> instead of simply Map<T, Set<T>>. As time progressed and people grappled with the language, I feel we learned to better manage these typing and get more sensible typing.
I think it is unfortunate Java doesn't do the conversion automatically but for the poor soul who may need an Optional<Optional<T>> one day, I'm willing to use map, flatMap, orElse, and ofNullable every once in awhile to keep my typing sane. Using those methods may help with your particular quandaries.
Edit:
I see, either missed it or an edit, that OP saw that Stream<Optional<T>>.first returns an Optional<Optional<T>>. What OP intends to do affects a compromise. They could .map the stream to strip the interior Optional or they could .filter & .map the stream to strip out empty Optionals. One sad, extra line of code.

Java: Compiler or Eclipse warning when attempting to use wrong type as Map key

I was recently bitten by a bug in which I had a Map with key type Long, but I attempted to use it with keys of type String. I essentially had something like:
Map<Long, Object> map;
...
String wrongType;
if (map.containsKey(wrongType)) {
// Do something
} else {
// Do something different
}
Because all of the keys in the map were of type Long, the code always executed the else block.
Since the containsKey and get methods take an argument of type Object, an object of any old type is accepted without complaint.
My confusion stemmed from the fact that the same entity is represented in two different ways in our system (sometimes as a Long, sometimes as a String); I can't easily change this. Is there any way I can catch an error like this while developing rather than during testing? Perhaps a compiler flag or some Eclipse option that is a little smarter about what sort of object I should be using with the containsKey and get methods (and their analogs in Set, too...)
FindBugs has a test for this: GC_UNRELATED_TYPES
Running FindBugs on your code should reveal this, and a lot of other things too ;-)
You can write a generic utility method that will provide type safety:
public static <T> boolean safeContainsKey(Map<T, ?> map, T key) {
return map.containsKey(key);
}
public static <T, U> U safeGet(Map<T, U> map, T key) {
return map.get(key);
}
Now you will get compile time errors if you pass in the wrong type:
//These compile fine
boolean result1 = safeContainsKey(map, 12345l);
Object obj1 = safeGet(map, 12345l);
//These cause compilation errors
boolean result2 = safeContainsKey(map, "12345");
Object obj2 = safeGet(map, "12345");
You could implement your own type safe version of the Map interface as well, but thats probably overkill.
Personally, I just run Google's CodePro Analytix which will provide useful type safety warnings.
The reason that the Map methods get() and contains() take Object (and not the type of the key) is they pre-date generics and to be backwardly compatible, the signatures had to stay that way.
Unfortunately, there is no compiler protection/warning against calling these methods with the wrong type.

What's the best way to deal with potential runtime exceptions from a java "unchecked conversion"?

So I have a function that looks like this:
#SuppressWarnings("unchecked")
public static <E> Set<E> getSetOfClass(Query q,Class<E> clazz) {
return new LinkedHashSet<E>( q.getResultList() );
}
What I believe this is doing is taking a javax.persistence.Query and returning its result set as a generic Set<Class>.
This seems like a great solution, but first off, is it actually doing what I think it is, and is this the best way to achieve that? I find it odd that I never reference my clazz param, but it does seem to do what I want it to.
Secondly if this is all correct and sensible, what errors can this throw? I'd imagine if I give it an incorrect class this function wouldn't work, though I'm not sure at all on that.
If I do something like:
Query q = em.createQuery("FROM Element");
Set<Fish> s = MyUtil.getSetOfClass( q, Fish.class);
And if Fish is not a superclass of Element then what happens? Should I assume that this function will always be used correctly or should I be doing so error handling? What are people recommendations of a best practice approach?
Regards,
Glen x
The getSetOfClass does not guarantee that all elements in the Set are objects of type E. If you call it incorrectly (what you always can), like:
Set<Cat> cats = getSetOfClass(findAllFish(), Cat.class);
you'll receive class cast exceptions at various places later on...
I'd add some checks to the public getSetOfClass method to guarantee that the content of the set matches the type parameter:
#SuppressWarnings("unchecked")
public static <E> Set<E> getSetOfClass(Query q,Class<E> clazz) {
return getSetOfClass(Query q,Class<E> clazz, true);
}
#SuppressWarnings("unchecked")
public static <E> Set<E> getSetOfClass(Query q,Class<E> clazz, boolean validate) {
List result = q.getResultList();
if (validate) {
for (Object o:result) {
if(!o.getClass().equals(clazz)) {
// handle error
}
}
}
return new LinkedHashSet<E>( result );
}
To add to #Andreas_D's answer, just remember that all Java generics information is only used to check your code for type correctness at compile time, and is erased at run-time. Therefore, effectively what you get is something like this:
public static Set<Object> getSetOfClass(Query q,Class<Object> clazz) {
return new LinkedHashSet<Object>( q.getResultList() );
}
Which means at runtime everything will just work, as far as the above method goes.
Update: As kindly pointed out by #Blaisorblade, the getSetOfClass method could use the clazz to check for type correctness and fail-fast if the type is wrong. Although it cannot be done at compile time, it'd make it easier to pin-point the problem in case of failure at runtime.
Now assuming that later you have:
Query q = em.createQuery("FROM Element");
Set<Fish> s = MyUtil.getSetOfClass( q, Fish.class);
for(Fish fish : s){
fish.swim();
}
Then at runtime it will look like:
Query q = em.createQuery("FROM Element");
Set<Object> s = MyUtil.getSetOfClass( q, Fish.class);
for(Object fish : s){
((Fish)fish).swim();
}
Now you can see what will happen if elements are of type Cat. The (Fish)fish part will throw a ClassCastException (if it gets that far).
Generics are therefore really useful when the type information can be tracked by the compiler without any unchecked warnings from beginning the the end. For other cases (like yours) where the generics is "hacked" in the middle, it cannot guarantee the correctness of you program. This is inevitable, especially in cases where the data is persisted to disk or a database, since there is no way to be sure that the persisted data is of correct type. The programmer has to just be careful.
I've never been sure whether I like generics or not. In this case it seems they would be a good idea and would have saved you a lot of trouble. As Persistence does not (yet) seem to support them, I'll put on my anti-generics hat and explain how real Java programming is done.
My suggestion, then, would be to give up on the generics and classes and just return a plain old Set:
public static Set getSetOfClass( Query q ) {
return new LinkedHashSet( q.getResultList() );
}
(use #SuppressWarnings("unchecked") as needed, if you can't get a 1.4 compiler.)
If the query contains nothing but E's, you'll never have a problem. Or at any rate, the trouble will be rare, obvious at run time, and best dealt with by the programmers who are misusing your method. Nothing says "Change your basic approach" like an unexpected ClassCastException at run time.
If there are the occasional, legitimate, non-E Fish objects in there, the programmers who are using the method are better placed to deal with them than you are. They can check at run time and optionally throw out the individual fish or toss the whole Set as suits their purpose, which they know and you do not.
If you do know their purposes, then you can perhaps save them some trouble by adding in the Clazz parameter so you know what they want. Then you can do the filtering or return a null or throw your own checked exception or return a special class object that explains in vast detail the nature of the Set contents. But be sure you don't do more work than you are saving the method's users.

Seeking explanation for Auto-Casting

So I just spent around an hour trying to unveil and resolve a very strange bug, one that I have never seen before.
I am more or less asking for potential causes of this seeming random cast from enum to String rather than "please fix my code for me".
The gist of the problem is as follows:
I have an interface, call it IFoo, within this interface, it has a static enum, called Bar:
public interface IFoo {
static enum Bar{
A,
B,
C,
}
Bar doGetBar();
}
I of course have a Foo class that implements IFoo.
public class Foo implements IFoo{
public Bar getBar(){
return Bar.A; // for example
}
}
Somewhere else, I have an object array called
Object[] result;
And a helper method that returns an array of Objects, holding results from the getBar()method, call it
public Object[] getBars()
Now, when I do
result = getBars();
result magically holds Strings instead of Bars, the values of the strings are the implementation class of the outer class (not really an outer class, more of a wrapper class?) of Bar, i.e. "Foo".
Could someone possibly explain to me how this is possible?
Some leads:
1. results were holding strings before the assignment.
2. the static enum inside IFoo is questionable, it was non-static, but it caused ClassCastExceptions when I tried to cast it to IFoo.Bar from Foo.Bar (or something along these lines).
Your Object[] has got Strings in it because you put them there. If you post a small example piece of code demonstrating clearly that you put Bars in but get Strings out I will be very surprised.
The method for resolving bugs like this is to start from the beginning, making a simple working example (which will likely not display the bug). Then keep adding code to make it more like your real-world application until the bug rears its head. Then you'll be able to identify your most recent change as the source of the bug.
It's not clear what "magic" is contained within the getBars() method, and without more information, It's not possible to produce a sample implementation to verify this behaviour. Specifically, it's not clear what "a helper method that returns an array of Objects, holding results from the getBar() method" means.
If you can, isolate the smallest test case containing the behaviour, as suggested. oxbow_lakes' suggestion is also good; bring a simple test as close to the real behaviour as possible.
If you really can't produce a simplified scenario to show us, then our ability to help you is going to be severely curtailed, since that getBar() method is where the Object[] is populated. In that case, if you can't work it out, then I suggest you may have to ask a more knowledgeable colleague for a bit of help - could be a second set of eyes will spot it.
Use collections and generics for type safety instead.
Edit As now the question changed to a conceptional level, I'll use my telesense to figure out the cause.
It seems you are reusing an Object[] array on line 252 for completely different purposes. The compiler accepts
Object[] objs = Bar.values();
//...
objs = "A B C".split("\\s+");
//...
return objs;
this kind of code because arrays in Java are covariant (e.g. String[] is subclass of Object[]). Reusing a base class object array this way is troublesome.
I am assuming that your getBars() method looks like this:
public Object[] getBars() {
return Bar.values();
}
if you are wondering what you should be receiving from the 'Bar.values()' method, check out the JavaDoc. In your case, values() would return type FooI$Bar.
It might be useful to post, not only the code that you have put together that throws the exception, but the ClassCastException as well.

Why is this generic method unsafe?

The following method generates a warning, but it looks safe to me. I'm sure the problem is with me:
public <S extends CharSequence> S foo(S s) {
return (S) new StringBuilder(s);
}
It looks like this will always return the argument s. Can anyone show an example that would cause this method to throw an exception?
Edit: I'm not particularly interested in the question of whether generics are necessary here. Rather, I'm looking for a demonstration of how this method is unsafe.
It's unsafe because while StringBuilder is a CharSequence, it isn't necessarily of type S (in fact, it almost certainly won't be). You can see this failing just by passing a String into your method. This will construct a StringBuilder using your String as an argument, and then try to cast your StringBuilder to String (which will fail).
There's probably no need to use generics here at all, this should work fine:
public CharSequence foo(CharSequence s) {
return new StringBuilder(s);
}
For example this will compile:
String a = foo("ss");
but it will fail at runtime:
ClassCastException: java.lang.StringBuilder cannot be cast to java.lang.String
since foo returns S, the type of your input parameter (String in this case).
I think that you don't need to use generics here (as skaffman said in his answer):
public StringBuilder foo(CharSequence s) {
return new StringBuilder(s);
}
foo("test");
is enough to make java try to cast a StringBuilder in a String.
Your code is guaranteed o be wrong, can you explain what you're trying to achieve plase ?
The unsafety here lies not within the method itself (though it has its problems, too) but at the call site. The use of S for the input argument's type as well as for the return value tells the compiler, that whatever the type of object may be that is passed to the function, the result has the same type (or a derived type, actually).
Thus, the compiler is allowed to assume, that in the call
foo("hello, world")
the result will be a java.lang.String, while in the call
foo(new StringBuffer("hello, world"))
the result will be a StringBuffer, and so on. In both cases, however, your method does not return what it was supposed to return, namely, an object of the same type as the input argument. Instead, a StringBuilder is returned.
Actually, the only kind of input argument your method will work with is a StringBuilder, anything else will be doomed to crash with a ClassCastException sooner or later, as the compiler might (and often does) insert (hidden) casts at the call sites.
And of course, as others have already pointed out, the use of generics is not really necessary here, anyway.
The return type of your method code is ALWAYS a StringBuilder.
That is because the declared type of the expression 'new StringBuilder(x)' is ALWAYS a StringBuilder, whatever the X.
It is TOTALLY pointless to try and cast this to anything. The "S" information is part of the erasure, which exists only at compile-time and is erased by the time the program runs, that is, run-time. (Casting is a run-time thing exclusively, and casting something to some type/class whose identity has been erased a run-time, is indeed totally pointless.)
my Java is rusty, but would this method not throw whatever exceptions
new StringBuilder(s)
can throw?

Categories

Resources