Categories
generics java raw-types

What is a raw type and why shouldn’t we use it?

770

Questions:

  • What are raw types in Java, and why do I often hear that they shouldn’t be used in new code?
  • What is the alternative if we can’t use raw types, and how is it better?

2

  • the java tutorials still use the JComboBox that causes this warning. Which version of the combobox will not cause this warning ? docs.oracle.com/javase/tutorial/uiswing/components/…

    – SuperStar

    Apr 2, 2013 at 10:04

  • 4

    Note that the reason why raw types exist is for backwards compatibility with Java 1.4 and older, which did not have generics at all.

    – Jesper

    May 23, 2016 at 8:07

67

What are raw types in Java, and why do I often hear that they shouldn’t be used in new code?

Raw-types are ancient history of the Java language. In the beginning there were Collections and they held Objects nothing more and nothing less. Every operation on Collections required casts from Object to the desired type.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

While this worked most of the time, errors did happen

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

The old typeless collections could not enforce type-safety so the programmer had to remember what he stored within a collection.
Generics where invented to get around this limitation, the developer would declare the stored type once and the compiler would do it instead.

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

For Comparison:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

More complex the Compareable interface:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

Note that it is impossible to implement the CompareAble interface with compareTo(MyCompareAble) with raw types.
Why you should not use them:

  • Any Object stored in a Collection has to be cast before it can be used
  • Using generics enables compile time checks
  • Using raw types is the same as storing each value as Object

What the compiler does:
Generics are backward compatible, they use the same java classes as the raw types do. The magic happens mostly at compile time.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

Will be compiled as:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

This is the same code you would write if you used the raw types directly. Thought I’m not sure what happens with the CompareAble interface, I guess that it creates two compareTo functions, one taking a MyCompareAble and the other taking an Object and passing it to the first after casting it.

What are the alternatives to raw types: Use generics

    32

    A raw type is the name of a generic class or interface without any type arguments. For example, given the generic Box class:

    public class Box<T> {
        public void set(T t) { /* ... */ }
        // ...
    }
    

    To create a parameterized type of Box<T>, you supply an actual type argument for the formal type parameter T:

    Box<Integer> intBox = new Box<>();
    

    If the actual type argument is omitted, you create a raw type of Box<T>:

    Box rawBox = new Box();
    

    Therefore, Box is the raw type of the generic type Box<T>. However, a non-generic class or interface type is not a raw type.

    Raw types show up in legacy code because lots of API classes (such as the Collections classes) were not generic prior to JDK 5.0. When using raw types, you essentially get pre-generics behavior — a Box gives you Objects. For backward compatibility, assigning a parameterized type to its raw type is allowed:

    Box<String> stringBox = new Box<>();
    Box rawBox = stringBox;               // OK
    

    But if you assign a raw type to a parameterized type, you get a warning:

    Box rawBox = new Box();           // rawBox is a raw type of Box<T>
    Box<Integer> intBox = rawBox;     // warning: unchecked conversion
    

    You also get a warning if you use a raw type to invoke generic methods defined in the corresponding generic type:

    Box<String> stringBox = new Box<>();
    Box rawBox = stringBox;
    rawBox.set(8);  // warning: unchecked invocation to set(T)
    

    The warning shows that raw types bypass generic type checks, deferring the catch of unsafe code to runtime. Therefore, you should avoid using raw types.

    The Type Erasure section has more information on how the Java compiler uses raw types.

    Unchecked Error Messages

    As mentioned previously, when mixing legacy code with generic code, you may encounter warning messages similar to the following:

    Note: Example.java uses unchecked or unsafe operations.

    Note: Recompile with -Xlint:unchecked for details.

    This can happen when using an older API that operates on raw types, as shown in the following example:

    public class WarningDemo {
        public static void main(String[] args){
            Box<Integer> bi;
            bi = createBox();
        }
    
        static Box createBox(){
            return new Box();
        }
    }
    

    The term “unchecked” means that the compiler does not have enough type information to perform all type checks necessary to ensure type safety. The “unchecked” warning is disabled, by default, though the compiler gives a hint. To see all “unchecked” warnings, recompile with -Xlint:unchecked.

    Recompiling the previous example with -Xlint:unchecked reveals the following additional information:

    WarningDemo.java:4: warning: [unchecked] unchecked conversion
    found   : Box
    required: Box<java.lang.Integer>
            bi = createBox();
                          ^
    1 warning
    

    To completely disable unchecked warnings, use the -Xlint:-unchecked flag. The @SuppressWarnings("unchecked") annotation suppresses unchecked warnings. If you are unfamiliar with the @SuppressWarnings syntax, see Annotations.

    Original source: Java Tutorials