In Java, when I get a ResultSet I made a method that would map that to a specified class. It more or less looks like this:
public <T> T mapRow(ResultSet results, Class<T> type) {
So, when I actually call the class, it looks like this:
mapRow(results, Row.class);
Please help me understand this conceptually.
Why can I not just do something like mapRow<Row>(results);?
Also, the current way I'm invoking mapRow, is there an implied <Row> before the method call?
You can call:
object.<Row>mapRow(results, Row.class);
but you still need the second parameter anyway, you cannot remove it for what you are trying to do.
This is because there is no way to know the type of T at runtime when mapRow is called, due to generics erasure.
the current way I'm invoking mapRow, is there an implied before the method call?
The point of the <T> T mapRow() declaration is that T is inferred from the method arguments or the LHS type to which the result is being assigned. In your case, you pass in a class object which serves to infer the return type.
The above is only one half of the purpose of the class argument, the second part being reflection: mapRow will call newInstance() on it to create the object to return.
Related
I've encountered the following code in a Java project, and I'm not sure what to make of it:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return ((Function<CustomEnum,String>) (someObject::toString)).andThen(r -> someObject::getSomethingWithEnumParameter);
}
I don't really understand how you can cast something to a Functional Interface. What does that even mean?
Isn't the resulting type of the return value going to be whatever value someObject.
Isn't Function<CustomEnum, String> defining an anonymous function that takes a type CustomEnum and returns a String?
I've read the java doc for Function<T,R>, and to be honest, this doesn't make much more sense than before I read the document.
This is what I believe is happening.
foo is returning an anonymous function that is applied to some CustomEnum to return a String
the anonymous function inside of foo (which is somehow cast onto someObject::toString, which I don't understand) is applied to the CustomEnum that will be passed from the initial call of foo(someObject).apply(customEnum).
The andThen will take the resulting String from the anonymous function inside of foo (which was cast somehow I still don't understand), and then return the value of someObject::getSomethingWithEnumParameter. Why isn't the return type just the type of someObject::getSomethingWithEnumParameter, which we'll say is a Map<R,T>, for sake of discussion.
If anyone could help me understand this flow, I would greatly appreciate it.
In an ideal world this would work:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return (someObject::toString).andThen(...);
}
However Java needs an interface type in order to implicitly create an interface instance from the method reference., hence the explicit cast is required to cast to the Function interface type.
Once you have an instance of Function then you can call any method on it as per normal, in this case the andThen method which composes it with another function object to form a new function.
Breaking it down:
someObject::toString is a method reference with implied type Function<CustomEnum, String>. I.e. toString is a method on SomeObject which takes a parameter of type CustomEnum and returns a String.
r -> someObject::getSomethingWithEnumParameter has the wrong type though - it's a function which returns a function. If you get rid of the "r ->" part then it is valid, as long as someObject::getSomethingWithEnumParameter is a method on SomeObject that takes a String and returns a String. Alternatively the return type of foo would need to change to Function<CustomEnum, Function<String, String>>.
If you combine those two with andThen then you have a Function which takes a CustomEnum and returns a String, as pr the return type of foo.
Here is the method I am calling:
public static <T extends Something> Group<T> getGroup() { ... }
If I wanted to store the result in a variable, I would do something like this:
Group<SomethingSubClass> group = StaticClass.getGroup();
How would I call the method without storing it in a variable?
StaticClass.getGroup();
The above is what I tried, but I am unsure (mostly don't think it is possible from the way my method is) to add the generic type T.
Solution:
StaticClass.<SomethingSubClass>getGroup();
You don't need anything special. Just invoke it as
StaticClass.getGroup();
You will simply be ignore the return value. The type argument will be inferred as Something, which is what you'd have access to in your method anyway.
You would specify an actual type argument by doing
StaticClass.<SomeTypeThatExtendsSomething>getGroup();
but you don't need that since the only part of your method that makes use of the generic type is the return type, which you are discarding.
Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?
I've a method in which I'm passing a generic argument. To execute one required method I need the class instance of the same. How can I get it.
There is a workaround which I'm using but I want to know how can we get the Class instance.
The snippet I'm using is:
public <T> T readModelWithId(Class<T> c, Serializable pk) {
// Some code here.
T t = (T)session.get(c, pk);
// Some code here.
return t;
}
The problem is that I don't want to pass the Class instance in this method as it is same as the return type T which is of generic type.
There's no way you can get to something like T.class within that method, so you must pass the class argument since you need it to get your model object from the session.
Moreover, this adds a bit of extra "type-safety". You will force the caller to specify the return type as an argument, so the returned type will not just be "anything a caller may expect" (although I agree this makes it redundant).
You can't do it because Java implements Generics using "type erasure".
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Looks like you are doing a generic DAO. I've done something similar here:
http://www.matthews-grout.co.uk/2012/01/my-generic-hibernate-dao.html
You cannot do anything with generics that you could not do with non-generics with casts. Consider the non-generic version of your code:
public Object readModelWithId(Class c, Serializable pk) {
// Some code here.
Object t = session.get(c, pk);
// Some code here.
return t;
}
Now ask the same question, can you get rid of the class instance argument c?
Generics are more for compile time type safety - you need class instance so compiler does not complain about missing cast. Alternatively you can ditch generics altogether and cast result
I am still experimenting with how Java handles generics. I stumbled upon the fact/issue/thing that if you have a generic interface like A<T>, you cannot really check afterwards if some object is actually implementing A<B> or A<C>.
I wondered if that could cause actual problems.
Now I have tried this code:
static interface A<T> { void foo(T obj); }
static class B implements A<B> {
public void foo(B obj) { obj.bar(); }
void bar() {}
}
static {
assert (new B() instanceof A<?>);
((A<?>) new B()).foo(new Object());
}
This gives me this error (for the foo-call):
The method foo(capture#1-of ?) in the type Main.A<capture#1-of ?> is not applicable for the arguments (Object)
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A<?> is foo(? obj) which I thought is the same as foo(Object obj).
The assert succeeds.
What I tried to figure out is at what point exactly does it cast the object when I call the foo function.
Also, how can I call foo from A<?>? This is the thing I actually need to be able to do. Or is that impossible with any other parameter than null?
A more real-world example where I actually wonder about this: I use the Comparable<T> interface a lot. That case is actually even more complicated; I might open another question about that if this here doesn't answer it.
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A is foo(? obj) which I thought is the same as foo(Object obj).
Nope, absolutely not. Imagine A<T> is List<T> with foo(T) being add(T) and so A<?> is List<?>. Should you be able to do this?
List<String> strList = new ArrayList<String>();
List<?> wcList = strList;
wcList.add(Integer.valueOf(6)); //possible if add(?) is same as add(Object)
//...
String str = strList.get(0);
Of course not, since you'd get a ClassCastException in the final line.
What foo(?) really means is that the method applies to some unknown but specific type. You can't typically invoke these methods unless you pass null as the parameter, which is acceptable to assign to any reference type.
If you have "foo(? obj)" then the ? could be any type. If it is say String then you can't pass, say, an Integer to it. All you can pass is null.
Casting and use of instanceof should normally be avoided unless unavoidable (such as implementing equals), particularly with generics.
The compiler is correct because it does a compile-cast test on compile-time.
((A<?>) new B()).foo(new Object());
is errornous because the compiler expected
((A<?>) new B()).foo(A object)....
meaning that it wanted anything of type A or its children. Object is the parent of A and it doesn't match the compile-test Parameter type for compilation.
When you check if an instance of B is an instance of A<?> you just do the same thing as new B() instanceof A. You don't really check how T is set, it's just "something".
Later in the code with the cast, you tell that you'll use B as a A<?> so the variable will have the characteristic of a A but the generic type is still "something". This "something" exists and is probably a specified class but your don't care of the exact type.
That's why when you use the foo() method which take a T in parameter, you can't pass a "something" in parameter, because you don't know what it is, it could be an Object but it could be anything else.
Because of this the compiler tells you foo(capture#1-of ?) isn't applicable for the argument Object. The needed parameter is "something" but not necessarily an Object.
Then, when would you need this feature ?
For example if you work with a map, if you don't really care of the type of the key (if you only work with the values() method for example), you could do something like this :
Map<?, V> m
This way you won't be able to use features related to the key of the map (but you don't care about that), but you'll be able to use a map with any kind of key.
No, foo(? obj) is not actually the same as foo(Object obj). The difference is, when the parameter type is Object, it's explicitly stating that any type of object is legal. With a parameter type of ?, the method states that it does not know what type of object is legal... therefore nothing is legal except for null.
The reasoning for this becomes apparent when you consider a List rather than an arbitrary interface. Look at this method:
public void foo(List<?> list) {
list.add(...); // what can we add here?
}
The ? indicates that any type of List is acceptable... the List passed in could be a List<String>, a List<Integer> or a List<Map<Foo, Bar>>. There's no way of knowing. Note that this is only a problem with methods that consume generic parameters, such as add or your foo method. For methods that produce (return) an object of the generic type, it's fine to use such a method and assign the result as an Object. This, unlike the consumer method, cannot corrupt the internal state of the generic object.
Also notice that when you call ((A<?>) new B()).foo(new Object()), you're trying to do something illegal... if something (such as the Object) that is not a B were to be passed to B's foo method, it would explode at runtime. The compiler is correctly preventing you from doing this.
You may also want to check out my answer to another question here which explains some things about bounded wildcard types and such.
This is a simple explanation:
A<?> means A of unknown parametrized type. Given
A<?> ref = new B()
ref could point to any A: A<Object, A<String>, anything. So you can not call A.foo(new Object()) because in case of A<?> reference there is no way to know which parameter ref.foo() accepts. Actually the only thing valid is ref.foo(null).
Many have clarified that point about ? but noone has really answered the main question yet, so here it is:
It is possible to call A#foo like this:
((A) new B()).foo(new Object());
The cast then is done inside of foo.