The following two methods compiles fine and do what they stand for.
public int returnArray()[]
{
int a[]={1 ,2};
return a;
}
public String[] returnArray(String[] array[])[]
{
return array;
}
According to this method signature, can't we somehow have a method signature like the following?
public <T>List rerurnList(List<T> list)<T>
{
return new ArrayList<T>();
}
This method is intended to return a java.util.List of generic type. It does not compile. It must be modified as follows for its successful compilation.
public <T>List<T> rerurnList(List<T> list)
{
return new ArrayList<T>();
}
Can't we have a method signature like the first cases, in this case?
For some reason Java lets you define arrays like in C, adding the [] modifier after the variable or method name. That, however, is not possible with generics.
Generic type arguments have to be declared right with the type, because they are part of the type descriptor. Arrays should also be declared that way, as they are also part of the type descriptor.
In order to understand why the compiler does not let you write things that way (and why it shouldn't let you write things like in the first examples), we need to break it down to pieces.
public int returnArray()[] { ... }
public: Visibility declaration
int: Return type, integer
returnArray: Method name
(): Argument list (empty)
[]: Whoops! the return type is actually an arrayof what we said before
This is even better:
public String[] returnArray(String[] array[])[]
public: Visibility declaration
String[]: Return type, an array of strings
returnArray: Method name
(String[] array[]): Argument list...
String[]: Type of the argument, array of strings
array: Name of the argument
[]: Whoops! argument type is actually an array of what we said before
[]: Whoops again! return type is actually an array of what we said before
Foot note: Don't do this, specify the types only in the types. Instead of String[] array[], use String[][] array.
Now that the array thing syntax is clear, and I hope you understand why it should be wrong, let begin with the generig thing:
public <T> List<T> rerurnList(List<T> list) { ... }
public: Visibility declaration
<T>: This method uses generic type T
List<T>: Return type, a generic List of T
rerurnList: Method name
(List<T> list): Argument list
List<T>: Argument type, generic List of T
list: Argument name
Just to answer your question: the syntax you're trying for the method that fails compilation is definitely wrong because of the <T> placed between the parameter list and the method body:
(List<T> list)<T>{
This is simply not valid Java syntax. That's not how you mark a generic method. You already marked the method as generic by putting the type parameter - <P> - between the method access modifier and its return type.
Related
To start with an example,
public static <T> T method(T str){
return (T)str;
}
// T is deduced to be a String
// This fails at compile time
Integer integer = method("Trial");
//Object obj = method("Trial"); // Old example
and,
public static <T> T method(String str){
return (T)str;
}
// What type does T gets deduced to in this case?
// This compiles but gives an error at run-time.
Integer integer = method("Trial");
//Object obj = method("Trial"); // Old example
Both code snippets compile fine. Which type does T get deduced to in the second example?
Non specified Generic Type is considered as Object so returned type is correct in both cases.
So which method is used ?
In fact, the most precise matching type will be accepted first. In your case method(String str) as "Trial" is a String.
// Will rename for understanding
// method(T str) => method1
// method(String str) => method2
public static <T> T method1(T str){
return (T)str;
}
public static <T> T method2(String str){
return (T)str;
}
// This is your implementation
Object obj = <Object> //as undefined
method2("Trial"); // as mentionned above
// BUT
Object obj = <Object> // as undefined
method1(1); // as 1 is an int upperbounded to Object
// AND
Object obj = <String>
method2("Trial");
Object obj = <String>
method(1); // will not compile
You should check this post for more details about overloading priorities
I am having a bit of a hard time following the question but anyways.
In your first example the return type is determined (inferred) by the passed in type of the method parameter (i.e String in that case). Consider the following example:
public static <T> T something(T something) {
return something;
}
And two calling examples:
String something = something("string");
Integer someOther = something("something");
The first one works OK but the second produces an error as the dynamically inferred return type is String whereas we attempt to store it an Integer variable.
Now the reason why this works fine when you assign both values to an Object variable is -- as mentioned above -- the fact that this is the upper bound of both String and Integer. In fact in you take a look a the disassembled class file using javap you'll see that your method's signature looks like this:
public static <T extends java.lang.Object> T something(T)
Note that all the above will effectively end up being Object types after compilation due to Java's type erasure.
On another sidenote, your example also casts the passed in parameter to T which is
redundant as this is handled by compiler's ability to infer types.
I suggest you take a look at the following:
https://www.baeldung.com/java-type-erasure
https://www.tutorialspoint.com/java_generics/java_generics_type_inference.htm
Now let's take into consideration your second example:
In that one, T will effectively and up to an Object type -- as I mentioned above. This is still the upper bound for the method but there is a caveat here. This method is wrong as it accepts the String object and attempts to cast it (wrong again) to the inferred type.
So for example I can do this (which compiles OK) but produces a ClassCastException on runtime:
public static <T> T something2(String something) {
return (T) something;
}
and this call:
Integer somethingOther = something2("sas");
Now as mentioned above the reason why this works when assigning to Object is that it is the parent classes of String and everything else.
The first function in your case has both data type of parameter and return type of function as T, which means both of them can be of any type. They can be string, integer, float, character, array, or anything else. The scope of this T type is restricted to this particular function only.
The second function has a data type of parameter as String, while the return type is T, meaning that only String type of values can be passed to this function.
For example,
public static <T> T func1 (T var)
{
return var;
}
The above function can have a = func1("String") or b = func1(2) or anything else. a will be of type String, and b will be of type int. On the other hand,
public static <T> T func2 (String var)
{
return var;
}
will return an error on func2(2).
Refer to Oracle Docs to get a detailed insight into Generic Methods.
Edit to Comment : When a function is being called, the Java compiler automatically infers the type of the parameter from the method arguments. When I invoke func1() in my example, I write func1("ABC"). The Java compiler is intelligent enough to now understand the T type of the argument is String. Similarly, I return a String type from func1, so the compiler will now know that the return type has to be String.
You can also go through https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html to study more.
I am new to generics and read in a article "A parameterized type, such as ArrayList<T>, is not instantiable — we cannot create instances of them".
Full quote, from Java in a Nutshell:
A parameterized type, such as ArrayList<T>, is not instantiable - we
cannot create instances of them. This is because <T> is just a type
parameter - merely a place-holder for a genuine type. It is only when
we provide a concrete value for the type parameter, (e.g.,
ArrayList<String>), that the type becomes fully formed and we can
create objects of that type.
This poses a problem if the type that we want to work with is unknown
at compile time. Fortunately, the Java type system is able to
accommodate this concept. It does so by having an explicit concept of
the unknown type which is represented as <?>.
I understand that it should not be instantiable since the concrete (actual) type is not known. If so, why does the below code compiles without an error?
public class SampleTest {
public static <T> List<T> getList(T... elements) {
List<T> lst = new ArrayList<>(); // shouldn't this line return an error?
return lst;
}
}
I know there is a gap in my understanding of generics here. Can someone point out what am i missing here?
Because T is given as another generic type argument.
It's the whole purpose of generics to make the type parameterizeable. So the caller can specify the type. This can be done in multiple layers: the caller may also be generic and let its caller specify the type.
public static void main(String[] args)
{
foo(7);
}
public static <T> void foo(T value)
{
bar(value);
}
public static <U> void bar(U value)
{
baz(value);
}
public static <V> void baz(V value)
{
System.out.println(value.getClass().getSimpleName());
}
It prints out
Integer
A parameterized type, such as ArrayList<T>, is not instantiable
Means: You cannot create ArrayList of an unknown T. It must be specified at compile time. But it can be done indirectly, by another generic. In your case, it's another T, which will be specified again by the caller of your generic getList.
The wildcard <?> is something different. It is used to specify compatibility. <?> is the syntax to avoid specification of the type. You can use extends to require a basetype or interface. However, you cannot create instances with wildcards.
List<?> list = new ArrayList<String>();
list = new ArrayList<Integer>();
This wouldn't be possible otherwise. It makes most sense when using it in parameter specifications, for instance:
public static int foo(List<? extends Comparable> list)
{
return list.get(1).compareTo(list.get(2));
}
It's very confusing of this book. It assumes that <?> somehow solves the problem that a List with unknown T cannot be instantiated. IMHO, this is rubbish. T must be specified to create an instance.
The code that you mention can compile because the Object "lst" is not actually initialized until the method is called. Since the method knows that it will be getting a var-args argument of type T, it can compile in this scenario. Take the example Wrapper class below for example:
public class Wrapper<T> {
public static <T> List<T> getList(T... elements){
List<T> lst = new ArrayList<>();
for(T element: elements) {
lst.add(element);
}
return lst;
}
}
This code can compile because the method hasn't been called. When the method is called, Type T will be the type that we pass as the var-args argument and the code will have no issue compiling. Lets test this in our main method:
public static void main( String[] args ){
System.out.println(Wrapper.getList("Hi", "Hello", "Yo"));
}
And the output is:
[Hi, Hello, Yo]
However, lets generate a compile-time error to see what the article is talking about within our main method:
Wrapper<T> myWrap = new Wrapper<>();
We are actually trying initialize a generic Object of the Wrapper class in the code above, but is unknown. Since the value for the placeholder will be unknown even when we call the method, it results in a compile-time error, whereas creating a List of type T within the getList method does not cause a compile-time error because it will be initialized with a type when the method is called.
once you call the method -> you are using a concrete value.
the method defines T and later you use it in the return type and the parameter list.
public static <T> List<T> getList(T... elements)
once you will send the first parameter from specific type -> the contract will force you for the next parameters.
List<? extends Object> list = getList("", 1); -> in this case java doesnt find common between string and integer so it uses the most basic connection "Object"
List<String> list2 = getList("test", "test2"); -> here you can see that because all of the parameters are Strings - java find that in common and use it as the T.
The specific passage from the book doesn't make any sense and is wrong. new ArrayList<T>() is perfectly fine provided that we are in the scope of a type parameter named T (either a type parameter of a generic class that we are in, or a type parameter of the generic method we are in).
new ArrayList<T>() can no less be instantiated than new ArrayList<String>() -- both compile to the same bytecode and both just instantiate an ArrayList object at runtime. The object doesn't know anything about its type parameter at runtime, and therefore no knowledge of T at runtime is needed to instantiate it. The type parameter in an instantiation expression of a parameterized type (new ArrayList<T>) is just used by the compiler to type-check the parameters passed to the constructor (there are none in this case) and to figure out the type returned by the expression; it is not used in any other way.
And by the way the method does not need to receive any parameters of type T, or of any type containing T, in order for this to work. A method that receives no arguments can still instantiate and return an ArrayList<T> perfectly fine:
public static <T> List<T> emptyList() {
List<T> lst = new ArrayList<T>();
return lst;
}
Also, the section in the book where this statement appears in doesn't really have anything to do with instantiation -- the section is about wildcards, and wildcards don't really have anything to do with object instantiation at all. So I am not really sure why they are mentioning it (incorrectly) there.
I've recently come across the java #SafeVarargs annotation. Googling for what makes a variadic function in Java unsafe left me rather confused (heap poisoning? erased types?), so I'd like to know a few things:
What makes a variadic Java function unsafe in the #SafeVarargs sense (preferably explained in the form of an in-depth example)?
Why is this annotation left to the discretion of the programmer? Isn't this something the compiler should be able to check?
Is there some standard one must adhere to in order to ensure his function is indeed varags safe? If not, what are the best practices to ensure it?
1) There are many examples on the Internet and on StackOverflow about the particular issue with generics and varargs. Basically, it's when you have a variable number of arguments of a type-parameter type:
<T> void foo(T... args);
In Java, varargs are a syntactic sugar that undergoes a simple "re-writing" at compile-time: a varargs parameter of type X... is converted into a parameter of type X[]; and every time a call is made to this varargs method, the compiler collects all of the "variable arguments" that goes in the varargs parameter, and creates an array just like new X[] { ...(arguments go here)... }.
This works well when the varargs type is concrete like String.... When it's a type variable like T..., it also works when T is known to be a concrete type for that call. e.g. if the method above were part of a class Foo<T>, and you have a Foo<String> reference, then calling foo on it would be okay because we know T is String at that point in the code.
However, it does not work when the "value" of T is another type parameter. In Java, it is impossible to create an array of a type-parameter component type (new T[] { ... }). So Java instead uses new Object[] { ... } (here Object is the upper bound of T; if there upper bound were something different, it would be that instead of Object), and then gives you a compiler warning.
So what is wrong with creating new Object[] instead of new T[] or whatever? Well, arrays in Java know their component type at runtime. Thus, the passed array object will have the wrong component type at runtime.
For probably the most common use of varargs, simply to iterate over the elements, this is no problem (you don't care about the runtime type of the array), so this is safe:
#SafeVarargs
final <T> void foo(T... args) {
for (T x : args) {
// do stuff with x
}
}
However, for anything that depends on the runtime component type of the passed array, it will not be safe. Here is a simple example of something that is unsafe and crashes:
class UnSafeVarargs
{
static <T> T[] asArray(T... args) {
return args;
}
static <T> T[] arrayOfTwo(T a, T b) {
return asArray(a, b);
}
public static void main(String[] args) {
String[] bar = arrayOfTwo("hi", "mom");
}
}
The problem here is that we depend on the type of args to be T[] in order to return it as T[]. But actually the type of the argument at runtime is not an instance of T[].
3) If your method has an argument of type T... (where T is any type parameter), then:
Safe: If your method only depends on the fact that the elements of the array are instances of T
Unsafe: If it depends on the fact that the array is an instance of T[]
Things that depend on the runtime type of the array include: returning it as type T[], passing it as an argument to a parameter of type T[], getting the array type using .getClass(), passing it to methods that depend on the runtime type of the array, like List.toArray() and Arrays.copyOf(), etc.
2) The distinction I mentioned above is too complicated to be easily distinguished automatically.
For best practices, consider this.
If you have this:
public <T> void doSomething(A a, B b, T... manyTs) {
// Your code here
}
Change it to this:
public <T> void doSomething(A a, B b, T... manyTs) {
doSomething(a, b, Arrays.asList(manyTs));
}
private <T> void doSomething(A a, B b, List<T> manyTs) {
// Your code here
}
I've found I usually only add varargs to make it more convenient for my callers. It would almost always be more convenient for my internal implementation to use a List<>. So to piggy-back on Arrays.asList() and ensure there's no way I can introduce Heap Pollution, this is what I do.
I know this only answers your #3. newacct has given a great answer for #1 and #2 above, and I don't have enough reputation to just leave this as a comment. :P
#SafeVarargs is used to indicate that methods will not cause heap pollution.
Heap pollution is when we mix different parameterized types in generic array.
For example:
public static <T> T[] unsafe(T... elements) {
return elements;
}
Object [] listOfItems = unsafe("some value", 34, new ArrayList<>());
String stringValue = (String) listOfItems[0]; // some value
String intValue = (String) listOfItems[1]; // ClassCastException
As you can see, such implementation could easily cause ClassCastException if we don't guess with the type.
Browsing through Guava libraries I saw this weird signature on a readLines method from Files class:
public static <T> T readLines(File file,
Charset charset,
LineProcessor<T> callback)
I know a little bit about generics in java, but this baffled me.
What does the double T mean here? And why is the first one in angled brackets?
UPDATE: Thanks for the answers. I am still not clear as to why I should use a T inside the brackets. Why for example can't it just be:
public static <> T readLines()
or
pulibc static <K> T readLines()
Or does the java syntax dictate that the SAME letter must be used?
Now this is even wierder:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
how can a method have a generic-return type and be void?
It's a generic method -- the T is called a type parameter, and can represent any type. So if I have a method with this signature:
public <T> T foo(T[] bar)
I can call it on any array, and it will return a single object of the same type. If I pass it a String array, I'll get back a String, and so on. More information in the Sun tutorials for "generic methods".
Edit: In answer to your updated question, bear in mind that the first <T> isn't part of the return type: it's just an indicator that T is a type parameter. So look at the example you quoted:
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
That just means that fromArrayToCollection will accept any array and any collection, but that they must be an array and collection of the same type. So you can pass in a String[] and a Collection<String>, or an Integer[] and a Collection<Integer>, but not a String[] and a Collection<Integer>. No matter what type you put in for T, the method returns nothing.
The first T inside the angle brackets mean that the method itself is generic. The second T is the return type. T can be any type within its bounds. In this case, T has no bounds.
T will be determined at the call site, and in this case, inferred from the LineProcessor<T> parameter.
I am still not clear as to why I should use a T inside the brackets. Why for example can't it just be:
public static <> T readLines()
or
public static <K> T readLines()
Or does the java syntax dictate that the SAME letter must be used?
The <T> or <K> is the type parameter. If you write <K> T, then the T isn't a type parameter - rather, you're using the specific class T. This won't work if you don't have a class that's literally named T in scope.
Now this is even wierder:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
how can a method have a generic-return type and be void?
It doesn't; the <T> is not a "generic return type", it's just the type parameter to the method. You're saying that the method is generic, and T is the type parameter. The return type of the method is void.
Instead of being generic at class level only the method readLines uses generics.
The first <T> declares the generic types used by the method
The following T is the return type.
The first one uses the same syntax as a generic class to declare the generic types. Instead you could write
class Generic <T>
{
public static T readLines(File file,
Charset charset,
LineProcessor<T> callback)
}
This however would make all instances of the class generic.
Extended Example:
public static <ElementType,ListType extends List<ElementType>> ListType add(ListType list,ElementType elem)
{
list.add(elem);
return list;
}
ArrayList<String> = add(add(new ArrayList<String>(),"Hello"),"World");
The method adds a given Element to a List and returns the List.
The method uses two generic Types one for the elements of the list and one for the list itself.
The names used are nothing special, using a T for a generic type is like using i for an integer.
ElementType is the name used for the generic Type of the elements (any valid variable name / identifier could be used)
ListType is the name for the generic list Type, the classes used have to extend/implement List for the ElementType.
The example calls the method with:
ElementType = String
ListType = ArrayList
which would result in
public static ArrayList<String> add(ArrayList<String> list, String elem)
Bloat end :-)
This is a generic method.
Actually there are three Ts, the third on LineProcessor<T> specifies T when you use the method.
"When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type. The type declared in the method argument is essentially replaced with the type you use when you instantiate the class.
If the class itself doesn't use a type parameter, you can still specify one for a method, by declaring it in a really unusual (but available) space-before the return type, This method says that T can be "any type of Animal"."
Can you explain?
What it means is that in a generic class, you can write methods like so:
public T doSomething () {
}
Note that the return type is 'T'.
At compile-time, the return type of that method will be whatever you have passed to the generic class when you instantiated it.
class Zoo<T> {
static void putAnimal(T animal) {
// do stuff
}
}
Zoo<Ape> apeZoo = new Zoo<Ape>(); // you can now put apes (and chimps) here
Zoo<Reptile> monkeyZoo = new Zoo<Reptile>(); // this zoo takes reptiles
apeZoo.putAnimal(new Chimp());
monkeyZoo.putAnimal(new Tortoise());
For the first paragraph, this is just how generics work for classes. For instance, for list, you can create a list of a generic type, such as integer, e.g.:
ArrayList<Integer> list = new ArrayList<Integer>();
(in real code you'd use List<Integer> of course)
Now ArrayList will be defined as:
public class Arraylist<T> { // implements....
// ...
public T get(int index) {
// ...
}
}
Which is what makes it possible to use the get method on list and get an Integer (because we made a class of type ArrayList<Integer> so T = Integer). Otherwise the compiler would have no idea what types of objects the list was storing and you'd have to get the method to return an Object, which is how it used to be.
What the second paragraph means is that you can add type parameters to methods just as you can to classes. e.g.:
public <T> void noOp(T element) {
// code here
}
This would allow you, for instance, to create a static utility method that returns something of type T. To return the first element of a List of T's:
public static <T> T getFirst (List<T> list) {
return list.get(0);
}
And you could use this method in a strongly typed fashion. Suggestions for better examples welcome. :-)
edit: I just realised I once wrote something that uses this functionality. I was using the JPA API and getting really annoyed at all the times you have to return something (a list, or a single item) from a query, and running into unchecked type warnings because there's no way to infer the type here. If you're like me and trying to avoid warnings in your code, you'd have to suppress the warnings every single time. So I wrote this method to suppress the warnings for me:
#SuppressWarnings("unchecked")
public static <T> List<T> returnResultList(Query query) {
return (List<T>)query.getResultList();
}
Which through the magic of type inference works on:
List<Integer> list = returnResultList(query);