0

Item 23 ( Don't use raw types in new code ) of Effective Java claims that using raw types in java code is always dangerous

For instance, it claims that the following method is dangerous and unsafe

// Use of raw type for unknown element type - don't do this!
static int numElementsInCommon(Set s1, Set s2) {
    int result = 0;
    for (Object o1 : s1)
        if (s2.contains(o1))
            result++;
    return result;
}

Although, I can see that doing any kind of write operation or class cast operation on s1 and s2 can lead to all kinds of exceptions, I dont understand why the above method is unsafe. Author Joshua Bloch goes on to recommend the following method instead.

// Unbounded wildcard type - typesafe and flexible
static int numElementsInCommon(Set<?> s1, Set<?> s2){
  int result = 0;
  for (Object o1 : s1)
    if (s2.contains(o1))
        result++;
  return result;
}

In other words, if a method only uses the methods of Object.Class and does not do any modifications to the parameters that are passed, why is it bad?

Karthick
  • 2,844
  • 4
  • 34
  • 55
  • 3
    In the long ago, before generics, people would **mix** types in the collections of the day (namely `Hashtable` and `Vector`, which were not collections in those days). That led to things like `[0, "abc", Date]`, which is a hack (because Java allows you to create your own datatypes). With `Set>` you are guaranteed a consistent element type. – Elliott Frisch May 30 '16 at 02:37
  • Sure. My question is, are raw type unsafe in case of read-only methods or operations that only involve methods exposed by **Object.Class** – Karthick May 30 '16 at 03:02
  • No, they are not. At runtime, all types are raw, and they do the exact same thing as the recommended method with the wildcards. But that method makes the compiler check that you don't actually do anything else than these "safe things". Without the wild card, you don't get an error for example if you accidentally add to your Set. So either use the generic type if you know it, or the wildcard if you don't. Don't use raw types. – Thilo May 30 '16 at 03:08

1 Answers1

2

It is bad in the sense that it prevents the compiler from type-checking more of your code.

Of course you can write good and safe code without it. People do it in Perl and Javascript every day. And even in Java, there is no difference between using raw types and using typed collections at runtime. But there is something to be said for having a compiler check as much as possible for you.

So, with a method like in your example, use wildcard types (Set<?>) instead of raw types. That way, if you do write "dangerous" code like s1.addAll(s2); the compiler will shout at you.

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Makes sense. I am surprised that the capture contraints from the interface are not enforced in the child classes. See https://gist.github.com/dsKarthick/e6b1b62c70f3722b13d9047aa338b8c2 for example. – Karthick May 30 '16 at 03:15
  • I think you do get a compiler warning about raw types in the child class. And if you do use types, they have to match the parent interface. – Thilo May 30 '16 at 03:18
  • The reason that you are even allowed to use raw types on the child class (or anywhere in Java, really) is backwards compatibility with old code from before Java5. But if you use types, they are properly enforced. – Thilo May 30 '16 at 03:19