questions:
- what raw types in java, , why hear shouldn't used in new code?
- what alternative if can't use raw types, , how better?
what raw type?
the java language specification defines raw type follows:
jls 4.8 raw types
a raw type defined 1 of:
the reference type formed taking name of generic type declaration without accompanying type argument list.
an array type element type raw type.
a non-
static
member type of raw typer
not inherited superclass or superinterface ofr
.
here's example illustrate:
public class mytype<e> { class inner { } static class nested { } public static void main(string[] args) { mytype mt; // warning: mytype raw type mytype.inner inn; // warning: mytype.inner raw type mytype.nested nest; // no warning: not parameterized type mytype<object> mt1; // no warning: type parameter given mytype<?> mt2; // no warning: type parameter given (wildcard ok!) } }
here, mytype<e>
parameterized type (jls 4.5). common colloquially refer type mytype
short, technically name mytype<e>
.
mt
has raw type (and generates compilation warning) first bullet point in above definition; inn
has raw type second bullet point.
mytype.nested
not parameterized type, though it's member type of parameterized type mytype<e>
, because it's static
.
mt1
, , mt2
both declared actual type parameters, they're not raw types.
what's special raw types?
essentially, raw types behaves before generics introduced. is, following entirely legal @ compile-time.
list names = new arraylist(); // warning: raw type! names.add("john"); names.add("mary"); names.add(boolean.false); // not compilation error!
the above code runs fine, suppose have following:
for (object o : names) { string name = (string) o; system.out.println(name); } // throws classcastexception! // java.lang.boolean cannot cast java.lang.string
now run trouble @ run-time, because names
contains isn't instanceof string
.
presumably, if want names
contain string
, could perhaps still use raw type , manually check every add
yourself, , manually cast string
every item names
. even better, though not use raw type , let compiler work you, harnessing power of java generics.
list<string> names = new arraylist<string>(); names.add("john"); names.add("mary"); names.add(boolean.false); // compilation error!
of course, if do want names
allow boolean
, can declare list<object> names
, , above code compile.
see also
how's raw type different using <object>
type parameters?
the following quote effective java 2nd edition, item 23: don't use raw types in new code:
just difference between raw type
list
, parameterized typelist<object>
? loosely speaking, former has opted out generic type checking, while latter explicitly told compiler capable of holding objects of type. while can passlist<string>
parameter of typelist
, can't pass parameter of typelist<object>
. there subtyping rules generics, ,list<string>
subtype of raw typelist
, not of parameterized typelist<object>
. consequence, you lose type safety if use raw typelist
, not if use parameterized typelist<object>
.
to illustrate point, consider following method takes list<object>
, appends new object()
.
void appendnewobject(list<object> list) { list.add(new object()); }
generics in java invariant. list<string>
not list<object>
, following generate compiler warning:
list<string> names = new arraylist<string>(); appendnewobject(names); // compilation error!
if had declared appendnewobject
take raw type list
parameter, compile, , you'd therefore lose type safety generics.
see also
how's raw type different using <?>
type parameter?
list<object>
, list<string>
, etc list<?>
, may tempting they're list
instead. however, there major difference: since list<e>
defines add(e)
, can't add arbitrary object list<?>
. on other hand, since raw type list
not have type safety, can add
list
.
consider following variation of previous snippet:
static void appendnewobject(list<?> list) { list.add(new object()); // compilation error! } //... list<string> names = new arraylist<string>(); appendnewobject(names); // part fine!
the compiler did wonderful job of protecting potentially violating type invariance of list<?>
! if had declared parameter raw type list list
, code compile, , you'd violate type invariant of list<string> names
.
a raw type erasure of type
back jls 4.8:
it possible use type the erasure of parameterized type or erasure of array type element type parameterized type. such type called raw type.
[...]
the superclasses (respectively, superinterfaces) of raw type erasures of superclasses (superinterfaces) of of parameterizations of generic type.
the type of constructor, instance method, or non-
static
field of raw typec
not inherited superclasses or superinterfaces raw type corresponds erasure of type in generic declaration correspondingc
.
in simpler terms, when raw type used, constructors, instance methods , non-static
fields also erased.
take following example:
class mytype<e> { list<string> getnames() { return arrays.aslist("john", "mary"); } public static void main(string[] args) { mytype rawtype = new mytype(); // unchecked warning! // required: list<string> found: list list<string> names = rawtype.getnames(); // compilation error! // incompatible types: object cannot converted string (string str : rawtype.getnames()) system.out.print(str); } }
when use raw mytype
, getnames
becomes erased well, returns raw list
!
jls 4.6 continues explain following:
type erasure maps signature of constructor or method signature has no parameterized types or type variables. erasure of constructor or method signature
s
signature consisting of same names
, erasures of formal parameter types given ins
.the return type of method , type parameters of generic method or constructor undergo erasure if method or constructor's signature erased.
the erasure of signature of generic method has no type parameters.
the following bug report contains thoughts maurizio cimadamore, compiler dev, , alex buckley, 1 of authors of jls, on why sort of behavior ought occur: https://bugs.openjdk.java.net/browse/jdk-6400189. (in short, makes specification simpler.)
if it's unsafe, why allowed use raw type?
here's quote jls 4.8:
the use of raw types allowed concession compatibility of legacy code. the use of raw types in code written after introduction of genericity java programming language discouraged. possible future versions of java programming language disallow use of raw types.
effective java 2nd edition has add:
given shouldn't use raw types, why did language designers allow them? provide compatibility.
the java platform enter second decade when generics introduced, , there enormous amount of java code in existence did not use generics. deemed critical code remains legal , interoperable new code use generics. had legal pass instances of parameterized types methods designed use ordinary types, , vice versa. requirement, known migration compatibility, drove decision support raw types.
in summary, raw types should never used in new code. you should use parameterized types.
are there no exceptions?
unfortunately, because java generics non-reified, there 2 exceptions raw types must used in new code:
- class literals, e.g.
list.class
, notlist<string>.class
instanceof
operand, e.g.o instanceof set
, noto instanceof set<string>
Comments
Post a Comment