Trying to create a static field with a generic type doesn't compile:
class MyClass {
public static Function<Z, Z> blargh = new Function<Z, Z>() {
public Z apply(Z a) {
return a;
}
};
}
Eclipse says:
Multiple markers at this line
- Z cannot be resolved to a type
- Z cannot be resolved to a type
- Z cannot be resolved to a type
- Z cannot be resolved to a type
- The type new Function<Z,Z>(){} must implement the inherited
abstract method Function<Z,Z>.apply(Z)
but replacing all the Zs with a concrete type works just fine:
static Function<Integer, Integer> blargh = new Function<Integer, Integer>() {
public Integer apply(Integer a) {
return a;
}
};
What's going on here?
Context:
I was originally trying to figure out why this code uses a method instead of a field:
public static <T extends Throwable> F<T, String> eMessage() {
return new F<T, String>() {
public String f(final Throwable t) {
return t.getMessage();
}
};
}
Maybe it's to overcome this restriction?
the Function type is from Google's guava library.
Edit: Now I see the problem better.
I think that firstly you would have to declare the type as a class parameter:
class MyClass<Z> {
to get visibility, but now the reason you can't use it like that is because the static member should be shared among all the instances of the class. But since you could create instances with different type parameters, the static member depending on a particular type would not make sense.
You can only use class-level generics on member fields. For example:
public class MyClass<Z> {
private Function<Z, Z> function;
// ...
}
is correct. Declaring this static instead will break. Why?
Think about ArrayList. Its class declaration is something like:
public class ArrayList<E> extends AbstractList<E> implements List<E>, ... {
// ...
}
E has no context in a static sense, because static variables belong to all instances of ArrayList, but E can be different for each ArrayList instance:
// Here's one ArrayList with E as String
List<String> strs = new ArrayList<String>();
// And another with E as Boolean
List<Boolean> bools = new ArrayList<Boolean>();
So because E can change from instance to instance, it doesn't make sense to have an E variable at the static level.
Now you can declare static methods with generics, but in a totally different way. For example, Collections.sort could have a declaration like this:
public static <T> void sort(List<? extends T> list, Comparator<T> comparator)
Notice that T is declared as part of the method before the return type. This is defining the context of T within the method, and T can differ from call to call.
Post-edit remark: in your case, you don't have Z declared anywhere, so you won't be able to use it anyway. See my declaration above for MyClass. Notice how I used <Z> directly on the class? That means that Z will be some arbitrary type.
In the case of what you were trying to figure out, you should look at Function as a generic way of representing a transformation. Let's dissect your posted method:
public static <T extends Throwable> F<T, String> eMessage() {
return new F<T, String>() {
public String f(final Throwable t) {
return t.getMessage();
}
};
}
First, note that this is a method, not a static field like your OP, so it's legal to have generics here. Also, it's static, so any generics need to be declared before the return type. Here, they declare <T extends Throwable>, so T must be some kind of error or exception that extends Throwable. The return type is F<T, String>, which is a function that takes a T (a Throwable) and returns a String. The actual object declares an f method which does just that by calling Throwable.getMessage. Since the project is functionaljava, everything is based on the F class, so generics are everywhere.
Just remember:
Generics declared at the class level can only be used by non-static members and methods.
Generics declared at the method level are allowable, but don't refer to the class-level types, referring instead to types declared before the return type.
Generics declared at the static field level simply aren't allowed because they'll never have context for their concrete type.
I think the simplest answer might be that: although the JDK compiler is flexible in how it interprets generics, it is impossible to modify or specify the "Z" class given the semantics of your code.
In all use of generics, you must define a syntax which specifies the identity of the generic class that is being operated upon. For example (As in the examples above).
1) Use a generic, parameterized utility function. In this case, its obvious to the compiler because the specified class is sent as input the function.
2) Define the class itself as being generic, and non static. This would then require that the user of the class declare it with the proper specified class parameter.
Specifically, for Function classes, you are clearly defining a constrained class : one which takes "Z" as input, and returns "Z" as output. If you want to generify this, you might create a FunctionFactory class, which takes in, for example, a single instance of Z, and returns a type-specified function of type :
public static <Z> Function<Z,Z> functionFactory(final Z default){
return new Function<Z,Z>(){
#Override
public Z apply(Z input) {
// TODO Auto-generated method stub
if(input==null)
return default;
else
return input;
}
};
}
Related
I've stumbled upon a piece of code that has me wondering why it compiles successfully:
public class Main {
public static void main(String[] args) {
String s = newList(); // why does this line compile?
System.out.println(s);
}
private static <T extends List<Integer>> T newList() {
return (T) new ArrayList<Integer>();
}
}
What is interesting is that if I modify the signature of method newList with <T extends ArrayList<Integer>> it doesn't work anymore.
Update after comments & responses:
If I move the generic type from the method to the class the code doesn't compile anymore:
public class SomeClass<T extends List<Integer>> {
public void main(String[] args) {
String s = newList(); // this doesn't compile anymore
System.out.println(s);
}
private T newList() {
return (T) new ArrayList<Integer>();
}
}
If you declare a type parameter at a method, you are allowing the caller to pick an actual type for it, as long as that actual type will fulfill the constraints. That type doesn’t have to be an actual concrete type, it might be an abstract type, a type variable or an intersection type, in other, more colloquial words, a hypothetical type. So, as said by Mureinik, there could be a type extending String and implementing List. We can’t manually specify an intersection type for the invocation, but we can use a type variable to demonstrate the logic:
public class Main {
public static <X extends String&List<Integer>> void main(String[] args) {
String s = Main.<X>newList();
System.out.println(s);
}
private static <T extends List<Integer>> T newList() {
return (T) new ArrayList<Integer>();
}
}
Of course, newList() can’t fulfill the expectation of returning such a type, but that’s the problem of the definition (or implementation) of this method. You should get an “unchecked” warning when casting ArrayList to T. The only possible correct implementation would be returning null here, which renders the method quite useless.
The point, to repeat the initial statement, is that the caller of a generic method chooses the actual types for the type parameters. In contrast, when you declare a generic class like with
public class SomeClass<T extends List<Integer>> {
public void main(String[] args) {
String s = newList(); // this doesn't compile anymore
System.out.println(s);
}
private T newList() {
return (T) new ArrayList<Integer>();
}
}
the type parameter is part of the contract of the class, so whoever creates an instance will pick the actual types for that instance. The instance method main is part of that class and has to obey that contract. You can’t pick the T you want; the actual type for T has been set and in Java, you usually can’t even find out what T is.
The key point of generic programming is to write code that works independently of what actual types have been chosen for the type parameters.
But note that you can create another, independent instance with whatever type you like and invoke the method, e.g.
public class SomeClass<T extends List<Integer>> {
public <X extends String&List<Integer>> void main(String[] args) {
String s = new SomeClass<X>().newList();
System.out.println(s);
}
private T newList() {
return (T) new ArrayList<Integer>();
}
}
Here, the creator of the new instance picks the actual types for that instance. As said, that actual type doesn’t need to be a concrete type.
I'm guessing this is because List is an interface. If we ignore the fact that String is final for a second, you could, in theory, have a class that extends String (meaning you could assign it to s) but implements List<Integer> (meaning it could be returned from newList()). Once you change the return type from an interface (T extends List) to a concrete class (T extends ArrayList) the compiler can deduce they aren't assignable from each other, and produces an error.
This, of course, breaks down since String is, in fact, final, and we could expect the compiler to take this into account. IMHO, it's a bug, although I must admit I'm no compiler-expert and there might be a good reason to ignore the final modifier at this point.
I don't know why this compile. On the other hand, I can explain how you can fully leverage the compile-time checks.
So, newList() is a generic method, it has one type parameter. If you specify this parameter, then the compiler will check that for you:
Fails to compile:
String s = Main.<String>newList(); // this doesn't compile anymore
System.out.println(s);
Passes the compile step:
List<Integer> l = Main.<ArrayList<Integer>>newList(); // this compiles and works well
System.out.println(l);
Specifying thetype parameter
The type parameters provide compile-time checking only. This is by design, java uses type erasure for generic types. In order to make the compiler work for you, you have to specify those types in the code.
Type parameter at instance-creation
The most common case is to specify the patterns for an object instance. I.e. for lists:
List<String> list = new ArrayList<>();
Here we can see that List<String> specifies the type for the list items. On the other hand, new ArrayList<>() doesn't. It uses the diamond operator instead. I.e. the java compiler infers the type based on the declaration.
Implicit type parameter at method invocation
When you invoke a static method, then you have to specify the type in another way. Sometimes you can specify it as a parameter:
public static <T extends Number> T max(T n1, T n2) {
if (n1.doubleValue() < n2.doubleValue()) {
return n2;
}
return n1;
}
The you can use it like this:
int max = max(3, 4); // implicit param type: Integer
Or like this:
double max2 = max(3.0, 4.0); // implicit param type: Double
Explicit type parameters at method invocation:
Say for instance, this is how you can create a type-safe empty list:
List<Integer> noIntegers = Collections.<Integer>emptyList();
The type parameter <Integer> is passed to the method emptyList(). The only constraint is that you have to specify the class too. I.e. you cannot do this:
import static java.util.Collections.emptyList;
...
List<Integer> noIntegers = <Integer>emptyList(); // this won't compile
Runtime type token
If none of these tricks can help you, then you can specify a runtime type token. I.e. you provide a class as a parameter. A common example is the EnumMap:
private static enum Letters {A, B, C}; // dummy enum
...
public static void main(String[] args) {
Map<Letters, Integer> map = new EnumMap<>(Letters.class);
}
Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.
I'm writing generic class
public class SomeClass<T> {
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
T min = c.iterator().next();
for (T element : c)
if (element.compareTo(min) < 0)
min = element;
return min;
}
}
public class Main {
public static void main(String[] args) {
SomeClass<Integer>.min(Arrays.asList(1, 2, 3)); // compile-time error
SomeClass.min(Arrays.asList(1, 2, 3)); // ok
}
}
In generic class SomeClass and generic method SomeMethod type-parameter T is the same or defference?
Why we have compile time-error on the string SomeClass<Integer>.min(Arrays.asList(1,2,3));?
The class declaration
public class SomeClass<T>
defines a generic class, where <T> specifies the type parameter (also called type variable). This introduces the type variable, T, that can be used anywhere inside the class.
And the method declaration:
public static <T extends Comparable<? super T>> T min(Collection<? extends T> c) {
...
}
defines a generic method. Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared.
Now if you want to call the generic method min, you need to call:
SomeClass.<Integer>min(Arrays.asList(1,2,3));
It's different, and you should never write code like this, specifically because of the possibility for confusion. Always use different type variables on classes and methods inside those classes.
T is for Type and you are accessing static method which has nothing to do with T.
Either use like this
SomeClass<Integer> a = new SomeClass<Integer>();
a.min(Arrays.asList(1, 2, 3));
OR
SomeClass.min(Arrays.asList(1, 2, 3));
The two Ts are different: the fist one is a parameter for the class (and is unused) and the second one is specific to the method. Since the method is static, the class parameter doesn’t affect it.
When you write SomeClass<Integer>.min(Arrays.asList(1, 2, 3));, you get an error because it doesn’t make sense to add a parameter to SomeClass since no object of that class is instanciated. SomeClass is only used to tell the compiler that you want to call a static method from that class. You can add a parameter to the method with SomeClass.<Integer>min(Arrays.asList(1, 2, 3));, but you don't have to since the compiler can infer the type here.
So what the compile message told you was that it's a syntax error. Why it's invalid syntax is easy to understand. You are trying to call a method on a type. That means you are calling a static method. Static methods are not within the scope of generic type parameters. So it is not allowed to put a generic type argument on the left side.
If you want the technical reason, it's because your method call expression is not one of the forms that's allowed by the syntax. The closest form to yours is TypeName . NonWildTypeArguments Identifier ( ArgumentListopt ). But TypeName (which is defined here) must be an identifier or package-qualified identifier. It does not allow brackets.
How can a similar functionality be achieved without errors?
class A<K> {
void f(K x) {}
}
void foo(A<? extends X> a, X x) {
a.f(x); // AN error: The method f(capture#1-of ? extends X) in the
// type A<capture#1-of ? extends X> is not applicable for the
// arguments (X)
}
I know that it happens because 'a' can be an instance of A<"non-X">, so its 'f' mustn't accept an instance of X as a parameter, but how can I force the parameters to be of the same type?
Here is more code:
Test class:
class Test {
<T> void foo(A<T> a, T x) {
a.f(x); // now it works!
}
}
In some class:
Container<X> container;
public void test() {
X x = new X();
new Test().foo(container.get(), x);
}
Here's the container class:
public class Container<K> {
A<? extends K> get() {
return new A<K>();
}
}
You can force the parameters to be of the same type by doing the following:
// the first class, A<K>:
class A<K> {
void f(K x) {}
}
// the second class, defining the method with generic type parameters
class Test {
<T> void foo(A<T> a, T x) {
a.f(x); // now it works!
}
}
// a third class, that uses the above two:
class Main {
public static void main(final String... args) {
final Test test = new Test();
final A<String> a = new A<>();
test.foo(a, "bar");
}
}
What this does is: the method foo defines a generic type parameter T and uses it to enforce that the K type parameter of the class A must match the type of x, the second parameter of foo.
You could even impose restrictions on <T> if you wish and if it makes sense for your problem, such as <T extends Bar> void foo(A<T> a, T x) {...}, or with super. You would want this if, as Joni asked on a comment in the question, X is actually a type and not a type parameter: you'd use <T extends X> void foo(...).
After you've shown more code, the problem becomes clear.
The method .get() of the container returns an instance of A<? extends K>. Therefore, the type parameter of the instance you obtain from .get() is not fully specified. Usually, it is not very good design to return such an unspecified type. For a video presentation with Joshua Bloch, the author of Effective Java and many APIs and features in Java, showing how to improve such an API, check this: http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22m. At exactly 25'36", Joshua Bloch says "don't try to use them [wildcard types] on return values", and he explains it later. Basically, you don't get any more flexibility by using them, and just makes it painfully hard for users of the API to deal with it (you just felt the effects of doing it...).
To fix, you could simply try to change the signature of .get() to A<K> get(), so the container class would be:
public class Container<K> {
A<K> get() {
return new A<K>();
}
}
Since you do know that get() is returning an instance of A<K>, there's no reason to use the older signature: it simply makes you lose information you already know!
And if this still doesn't work, your problem might be somewhere else, and you'd need to show even more code... or better still, ask other questions! :)
Keeping in mind the PECS rule, and given the way you are using X, you should be specifying as a lower instead of upper bound:
void foo(A<? super X> a, X x)
This way no compiler errors are produced, and you have the most general signature applicable.
Consider the following constructor for the class Foo (which for the sake of clarity is not a generic class):
public <T> Foo(T obj) { }
This is valid syntax for constructors, just like with normal generic methods.
But what is the use of this syntax? Typically generic methods provide type safety for their return type, and can benefit from type inference by the compiler. For example:
Pair<String, Integer> stringInt = Pair.of("asfd", 1234);
But a call to a constructor always returns an instance of its declaring class, so its type parameters have no effect on the return type. The constructor above could just be replaced with its erasure:
public Foo(Object obj) { }
Of course generics aren't only about type safety for return types. The constructor might just want to constrain the type of argument(s) being passed in. However, the above reasoning still applies for a bounded type parameter:
public <N extends Number> Foo(N number) { }
public Foo(Number number) { } //same thing
Even nested type parameters with bounds are handled using wildcards:
public <N extends Number, L extends List<N>> Foo(L numList) { }
public Foo(List<? extends Number> numList) { } //same thing
So what is a legitimate use case for having a generic constructor?
Here's a possible one, adapted from functional programming. Suppose we have a Stream type that has some internal state, repeatedly yielding new elements until it returns null. The outside callers don't care what the internal state type of the stream type is, so you might get something like
class Stream<E> {
<S> Stream(S initialState, StepFunction<E, S> stepFun) {
...
}
}
without the recipient having to know what the internal state type is.
One thing I can think off of the top of my head is that you can ensure that bounds are fulfilled in the same way across multiple parameters.
Take an obviously stupid and contrived but valid constructor that copies a list from a source to a target:
public <T> Foo (List<T> listA, List<T> listB) {
listA.addAll(listB);
}
Using wildcards here would quickly become pretty nasty and probably not do what you want anyway. It would also be a totally arbitrary restriction to disallow it. So it makes sense to me that the language spec allows it.
One use case that I can think of is when you want to constrain a constructor argument to more than one type. Only the generic syntax allows you to declare a constructor taking a List of Numbers that also implements RandomAccess:
public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { }
...
Foo f1 = new Foo(new ArrayList<Integer>());
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error
You can enforce certain constraints for the constructor parameters. E.g. the following code requires two parameters which implement the interfaces InterfaceA and InterfaceB.
<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {
}
The main use is to ensure that type constraints are met between multiple parameters. Here's an example that puts a bunch of components on an assembly line in the right order:
public <T> AssemblyLine(T[] starting, List<T> components) {
T[] a = components.toArray(starting);
Arrays.sort(a);
this.conveyorBelt.add(a);
}
Here the <T> ensures that T[] and List<T> hold the same type T, and not (say), Integer[] and List<string>.