I am writing a function called arrayToMap(). I was originally going to just allow String arrays, but I thought I could make it generic so any type of array. I tried the following code snippet but it tells me T cannot be resolved to a type:
public Map <T, Integer> arrayToMap( T [] arr ) {
assert( arr != null ) : "arrayToMap null array";
Map<T,Integer> res = new HashMap<>();
int ind = 0;
for ( T val: arr ) {
res.put(val, ind);
ind++;
}
return res;
}
What is the correct syntax?
The signature should be changed to this:
// Notice the <T>, this is a generic method declaration
public <T> Map <T, Integer> arrayToMap( T [] arr )
This is called a generic method and you can read more about it here. Just like generic type declarations (classes and interfaces), method declarations can also be generic which means that they can be parameterized by one or more type parameters such as the <T> in the example above.
However, if your class is a generic class i.e. it is declared as a generic type the signature can stay the same as in the original example.
// A generic type declaration <T>
public class MyClass<T> {
// The type T comes from the generic type declaration,
// therefore the generic method declaration is not needed
public Map<T, Integer> arrayToMap(T [] arr) {
...
}
}
But, a generic class is likely not a good approach for the OP:s original use case since the arrayToMap method kind of implies that it is a general method that can be used on any type of array.
Related
As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.
I am new to Java. In this document they give this as a use case for using wildcard:
static void printCollection(Collection c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
This is their solution:
static void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
But I could do the same without a wild card:
static <T> void printCollection(Collection<T> c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
Can someone show me a simple use case where regular generics won't work but a wild card will?
Update: The answers over here When to use wildcards in Java Generics? do NOT tell us the need for wildcard. In fact its the other way around.
One thing wildcards allow us to do is declare types that are agnostic towards a particular type parameter, for example a "list of any kind of list":
List<List<?>> listOfAnyList = ...;
listOfAnyList.add( new ArrayList<String>() );
listOfAnyList.add( new ArrayList<Double>() );
This is impossible without a wildcard:* because the element lists may have different types from each other.
And if we try to capture it, we will find that we can't:
static <E> void m(List<List<E>> listOfParticularList) {}
m( listOfAnyList ); // <- this won't compile
Another thing wildcards allow us to do that type parameters cannot is set a lower bound. (A type parameter can be declared with an extends bound, but not a super bound.**)
class Protector {
private String secretMessage = "abc";
void pass(Consumer<? super String> consumer) {
consumer.accept( secretMessage );
}
}
Suppose pass was instead declared to take a Consumer<String>. Now suppose we had a Consumer<Object>:
class CollectorOfAnything implements Consumer<Object> {
private List<Object> myCollection = new ArrayList<>();
#Override
public void accept(Object anything) {
myCollection.add( anything );
}
}
The problem is: we can't pass it to a method accepting Consumer<String>. Declaring Consumer<? super String> means that we can pass any consumer which accepts a String. (Also see Java Generics: What is PECS?.)
Most of the time, wildcards just let us make tidy declarations.
If we don't need to use a type, we don't have to declare a type parameter for it.
* Technically also possible with a raw type, but raw types are discouraged.
** I don't know why Java doesn't allow super for a type parameter. 4.5.1. Type Arguments of Parameterized Types may hint that it has something to do with a limitation of type inference:
Unlike ordinary type variables declared in a method signature, no type inference is required when using a wildcard. Consequently, it is permissible to declare lower bounds on a wildcard […].
T stands for the generic type of that data structure. In your last example, you don't use it, and its NOT an actual type (for example String), and because you don't use it it doesn't really matter in this case.
For example, if you had a Collection and tried to pass it to a method that accepts a Collection, that works because there is no type T on the classpath so its considered a variable. If you tried passing the same Collection to a method that accepts a Collection, that would not work because you have String on your classpath so its not a variable.
Take List as the example.
List<?> can be the parent class of List<A>.
for instance,
List<B> bList = new ArrayList<>(); // B is a class defined in advance
List<?> list = bList;
you can never use <T> in this situation.
<?> has the wildcard capture.
here,
void foo(List<?> i) {
i.set(0, i.get(0));
}
the code above cannot be compiled. You can fix it:
void foo(List<?> i) {
fooHelper(i);
}
// wildcard can be captured through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
see more, http://docs.oracle.com/javase/tutorial/java/generics/capture.html
I can only think of the two currently, later may update.
Suppose I have a method:
public class AwesomeClass {
public <E> List<E> convertIterableToList(Iterable<E> iterable) {
...
}
}
At runtime, how can I resolve the method's return type based on the argument type? For example, I wish to implement a hypothetical method resolveReturnType whose behavior is demonstrated in this little (pseudo-Java) unit test:
Method method = AwesomeClass.class.getDeclaredMethod("convertIterableToList", Iterable.class);
Type argumentType = {{{Set<String>}}}; // Just pretend this syntax works. :)
Type expectedReturnType = {{{List<String>}}};
Type actualReturnType = resolveReturnType(method, argumentType);
assertEquals(expectedReturnType, actualReturnType);
So far, I have been trying to use Guava's TypeToken class but I have been not making much progress.
So, this is actually possible, provided that you have the actual formal Types of the arguments to the method available. As #JvR notes, this isn't possible in general at runtime, but if (as in your example) you are able to explicitly specify those types using TypeToken or some such, it does work.
static Type resolveReturnType(Type classType, Method method, Type... argTypes) {
// this should resolve any class-level type variables
Type returnType = TypeToken.of(classType)
.resolveType(method.getGenericReturnType()).getType();
Type[] parameterTypes = method.getGenericParameterTypes();
TypeResolver resolver = new TypeResolver();
for (int i = 0; i < parameterTypes.length; i++) {
#SuppressWarnings("unchecked") // necessary for getSupertype call to compile
TypeToken<Object> paramType =
(TypeToken<Object>) TypeToken.of(parameterTypes[i]);
#SuppressWarnings("unchecked") // necessary for getSupertype call to compile
TypeToken<Object> argType =
(TypeToken<Object>) TypeToken.of(argTypes[i]);
if (method.isVarArgs() && i == parameterTypes.length - 1) {
// TODO
} else {
TypeToken<?> argTypeAsParamType =
argType.getSupertype(paramType.getRawType());
resolver = resolver.where(
paramType.getType(), argTypeAsParamType.getType());
}
}
return resolver.resolveType(returnType);
}
There are some holes in the above code: for example, it won't resolve the return type of E foo(E[] array) correctly given an argument type of String[]. It also can't help with any generic method whose return type has a type variable that is not used in its parameter types, of course. I also haven't tried it with various other things, like wildcards. But for your example it works, and it also handles type variables declared by the class (if it's an instance method) in addition to those declared by the method:
public class Foo<T> {
public <E> Map<T, E> convertIterableToMap(Iterable<E> iterable) {
return null;
}
public static void main(String[] args) throws Exception {
Method method = Foo.class.getMethod("convertIterableToMap", Iterable.class);
Type instanceType = new TypeToken<Foo<Integer>>() {}.getType();
Type setOfString = new TypeToken<Set<String>>() {}.getType();
// prints: java.util.Map<java.lang.Integer, java.lang.String>
System.out.println(resolveReturnType(instanceType, method, setOfString));
}
}
Short answer: you can't.
Longer answer:
<E> List<E> convertIterableToList(Iterable<E> iterable) has a type E that is not generally reifiable. You could check whether the supplied iterable has fixed this type (1) in its class definition, which means you could retrieve that and figure out what E means in that specific invocation.
But in the general case, the runtime won't know what E is for any specific invocation.
(1) Meaning something like class StringList implements List<String> where the type variable is fixed.
I am currently new to working with Java. So far I have been able to easily use the basic such as Classes, Functions, Arrays etc from my knowledge of JavaScript and PHP.
However, what I have never seen before is this: <>. Inside of that is a variable of some type. Because I don't know what it is called, I can't find any answers.
I've seen them like this:
List<String> myList = new ArrayList<String>();
But also like:
public static <T> boolean contains( final T[] array, final T v ) {
for ( final T e : array )
if ( e == v || v != null && v.equals( e ) )
return true;
return false;
}
What does the <String> mean?
In the function, I was also wondering what is specifically special about the T?
This is for a Generic type
What it allows you to do is to pass through a type, and make it useful for multiple object types
So List is a generic collection, and it allows you to make a list of any object. Making List<String> will make the object be a list of Strings. Or you could use List<MyClassType> and it would make a list of objects of your class
That defines the Type of the objects a collection can hold
so when you write List<String> myList = new ArrayList<String>();, it means
Create an arrayList that can hold the String objects.
SomeParameterizedClass{
T someValue;
}
means that you can pass your type to the class e.g. SomeParameterizedClass<String> so that someValue becomes of type String
When you write List<T> list = new ArrayList<T>();, here T can be any type.
With java 7 you can simply say List<String> list = new ArrayList<>();. It has the same meaning.
In java 7 <> is called as diamond operator
You will find < > in the following cases, the T is a "parameter type" in plain English that means you could "substitute" that T by any other non-primitive type (like String or Integer):
When you are declaring a parameterized Type:
class MyParameterizedClass<T> {
public T myValue;
}
When you are declaring variables of your parameterized type:
MyParameterizedClass<String> myStringParam;
MyParameterizedClass<Integer> myIntegerParam;
When you are using constructors of parameterized types:
MyParameterizedClass<String> myStringParam = new MyParameterizedClass<String>();
MyParameterizedClass<Integer> myIntegerParam = new MyParameterizedClass<Integer>();
myStringParam.myValue = "Hello world";
myIntegerParam.myValue = 5;
When you declare a generic method:
public <T> T updateMyValue(T myValue) {
this.myValue = myValue
}
What you have observed is partially correct! In Java, inside <> should be 'Object' type or any subclass type of 'Object'.
When you declare myList as below:
List<String> myList = new ArrayList<String>(), it ensures the declared and initialized myList has elements of only String type. This is called type declarations.
public static <T> boolean contains( final T[] array, final T v ) { }, is a generic method declaration which implies that the passed two parameters should be of same object type, 1st parameter an array, 2nd parameter an object. And the method return type also should be same type.
Refer Java docs for more examples on Generics. http://docs.oracle.com/javase/tutorial/extra/generics/methods.html
Type Variables' bounds can only appear in the declaration of classes, interface, methods and constructors?
Or can I bound a type variable when they are used as type arguments?
Edit:
Example:
class MyClass<T extends Number> { // T is bounded by the interface Number
// can a bounded Type Parameter appear anywhere else,
// besides the Type parameter declaration?
}
The Java Language Specification seems to agree with you:
A type variable (§4.4) is an
unqualified identifier. Type variables
are introduced by generic class
declarations (§8.1.2) generic
interface declarations (§9.1.2)
generic method declarations (§8.4.4)
and by generic constructor
declarations (§8.8.4).
Consider this static method:
public static <T> List<T> filter(final List<T> orig, final Predicate<T> pred) {
return new ArrayList<T>() {{
for (T t : orig) if (pred.allow(t)) add(t);
}};
}
The "value" of "T" is "bound" by each call. Now, it's not really bound at the time the method is invoked; it's "bound" at compile time by inspection of the static particulars of each invocation as it appears elsewhere.
Thus if somewhere I call it like this:
final List<Integer> numbers = Whatever.filter(origList, new Predicate<Integer>() {
public boolean allow(Integer i) {
return i != null && i.intValue() > 0;
}
});
then "T" is "Integer".
Yes. Type Bounds are applied in the declaration of Type Variable.
In other words - when Type Variable appears for the first time.
public class MyClass<T extends MyItem> { // <- Type declaration
private T item; // <- Type usage
public <K extends T> K getSubitem() {
// ^ ^
// declaration usage
...
Arrays.<K>asList(); // <- Type Usage not a type declaration
}
}