What am I do wrong?
There are a few things wrong, but the compiler isn't stopping you doing them because you're using a raw type (see: What is a raw type and why shouldn't we use it?):
CatToKittenFunction function
CatToKittenFunction
is an interface with two type variables. You either have to specify two type parameters (correct usage); or no type parameters (incorrect usage, this makes it a raw type).
Raw types disable type checking of things using them. So, rather than this being, say, a function which turns a Kitten
into a Cat
, it's a function which turns an Object
into an Object
. This is why you have to explicitly cast to Cat
with (Cat)
.
Because it returns an Object
, the compiler doesn't know whether casting it to Cat
will fail. It could succeed (all Cat
s are Object
s), but it could also fail (not all Object
s are Cat
s). Fortunately, the cast to Cat
is a checked cast, so it will immediately detect if it's not a Cat
, and throw a ClassCastException
.
A ClassCastException
is bad, insofar as it's a runtime failure; but it's at least good insofar as it is thrown very close to where the problem occurs. The failures that tend to result from raw types, heap pollution, can occur far from and long after the problem was actually introduced.
The CatToKittenFunction
you're passing in is not a CatToKittenFunction<Kitten, Cat>
, it's a CatToKittenFunction<Object, ? extends Class<?>>
- you're taking in some object, returning its class. A Class
isn't a Cat
, so this cast is going to fail with a ClassCastException
.
If you expect your function to take in a Kitten
, and return a Cat
, specify that in the parameter type:
CatToKittenFunction<Kitten, Cat> function
or, drop the type variables from the interface:
public interface CatToKittenFunction {
Cat grow(Kitten k);
}
so this always converts a Kitten
to a Cat
.
With either approach, now your lambda s -> s.getClass()
simply won't compile.
You just need to work out how to create your Cat
from your Kitten
. For example:
s -> new Cat(s.age() + 1, s.name())