Raw Types in Java

Raw Types in Java

Have you ever used a generic class in Java Programming without giving it a type? That is called a Raw Type in Java. It might look fine, but it can cause problems in your code, like errors when your program is running. But why does Java still allow raw types? Are they useful, or should we stop using them completely?. In this blog, we’ll explain what a Raw Type in Java is, why it is not safe to use, and what you should do instead to make your code better and safer.

Table of Contents:

What is a Raw Type?

A raw type is a generic Java class or interface that is used without its type parameter. Raw types were commonly used before Java 5. In modern Java, raw types are still valid for backward compatibility with legacy (pre-Java generics) code, but are discouraged due to their lack of type safety. This relates to type erasure, the process by which the Java compiler removes all generic type information during compilation, treating generic types as their raw counterparts at runtime. Because of this, type errors involving raw types are not caught at compile time and may lead to unexpected failures during execution.

Example:

ArrayList list1 = new ArrayList();
ArrayList<Integer> list2 = new ArrayList<>();

In the above example, list1 is a raw type, and list2 is not.

Let us understand them with the help of an example. Consider the following Java code:

Java

Output:

What is a Raw Type

In the above Java code, the ArrayList is defined without a type parameter. The value “Hello” and 42 are added to it. When the list is iterated by the object obj, it fails to understand the type of the value. Hence, the runtime error is thrown. 

ArrayList vs ArrayList (raw):

Feature ArrayList<T> ArrayList (Raw Type)
Type Safety Enforced at compile time Not enforced
Type Checking Compile-time checks Possible runtime ClassCastException
Requires Type Parameter Yes No
Backward Compatibility Not needed Used for legacy support
Example ArrayList<String> ArrayList
Master Java Today - Accelerate Your Future
Enroll Now and Transform Your Future
quiz-icon

Why Should You Not Use the Raw Type in Java?

One should not use the raw type for the following reasons:

1. How Raw Types in Java Cause Loss of Type Safety?

It ensures that the variables, method parameters, etc., are using the same data type. When the raw types are used, they mix the different types of data, which can cause a ClassCastException at runtime. ClassCastException occurs if an Integer is converted to a String.

Example:

Java

Output:

Loss of type safety in Java

Explanation: In the above Java program, the type of ArrayList is not specified during its declaration, and a String and an int are added to it. This does not cause a compile-time error but results in a runtime failure.

2. Unchecked Warnings Caused by Raw Types in Java

When using raw types, Java cannot get the data type safety at compile time, due to which it gives unchecked warnings.

Java

Output:

Unchecked warnings in Java

Explanation: In the above Java program, the data type of the list is not specified by the user. Because of this, the compiler gives the warning of the [checked] checked call.

3. Why Parameterized Types Don’t Work with Raw Types in Java?

Generic methods allow other methods to be type-safe by using type parameters. However, when raw types are used, generic methods cannot function properly.

Example:

Java

Output:

Cannot use generic methods

Explanation: In the above code, the program runs correctly, giving the output “Hello”. But the method used is not safe here.

Unlock Your Future in Java
Start Your Java Journey for Free Today
quiz-icon

4. Why Raw Types Don’t Work with Parameterized Types in Java?

Generic constraints are not considered when a raw type is used; hence, they are not compatible with bounded types.

Example:

Java

Output:

Doesn’t work with the parameterized type

Explanation: In the above code, using a raw type Box rawBox = new Box(); disables the type safety and allows mixed types, String and Integer, which causes runtime errors like ClassCastException. 

5. Runtime Issues Caused by Using Raw Types in Java

When using the raw types, Java does not check the type of the data being used. This can cause runtime errors in the program. For example, if you are using different types of data in the list, the program may not run, which can lead to a ClassCastException.

Example:

Java

Output:

 Problems at runtime

Explanation: The list of strings is created in the above Java code. The value 1 is being inserted in the list using the method of raw type, which further leads to a ClassCastException at runtime

How Java Handles Raw Types Internally?

From the compiler’s perspective, raw types are handled through the mechanism of type erasure, which removes all generic type information during compilation. Here’s how Java processes raw types internally:

1. Type Parameter Removal
When a generic class (e.g., ArrayList<T>) is used as a raw type (ArrayList), the compiler erases the type parameter. It treats all instances of the generic class as if they had an object as their type parameter.

ArrayList rawList = new ArrayList();       // Treated as ArrayList<Object>
rawList.add("Hello");                      // Allowed, but unchecked

2. Unchecked Warnings
The compiler issues unchecked warnings when raw types are used, particularly during assignments, method calls, or conversions between generic and raw forms.

ArrayList<String> list = new ArrayList();  // Warning: unchecked conversion

3. Method Signature Translation
When methods in generic classes are compiled, their signatures are rewritten using erased types.
So:

public class Box<T> {
    public T get() { ... }
}
becomes internally:
public class Box {
    public Object get() { ... }  // T is erased to Object
}

When used as a raw type, the compiler doesn’t generate compile-time type checks on the return or argument types, relying on the developer to perform explicit casts if needed.

4. Backward Compatibility Enforcement
The compiler ensures that generic code remains compatible with legacy raw-type-based code. For example, a method written before generics can still interact with generic classes without breaking existing binaries.

5. Suppression via Annotations
Developers can suppress unchecked warnings using @SuppressWarnings(“unchecked”) — but this shifts responsibility for correctness to the developer.

In summary, the Java compiler removes all generic type information for raw types, defaults to Object where type parameters were, and allows raw types to function at the cost of type safety, issuing warnings instead of enforcing strict checks.

What to Use Instead of Raw Types in Java?

If you use raw types instead of generics, it will be harder to read and maintain, leading to error-prone code, and will also give unexpected errors. To overcome this, Java provides various alternatives to raw types:

1. Generic Types: Always specify type parameters when using collections or custom generic classes to enforce type safety.

Syntax:

ArrayList<String> list = new ArrayList<>();

2. Unbounded Wildcards (<?>): Use when you need flexibility but don’t require a specific type.

Syntax:

List<?> wildcardList = new ArrayList<>();

3. Bounded Wildcards (<? extends T> or <? super T>): Use when working with specific type hierarchies.

Syntax:

List<? extends Number> numberList = new ArrayList<Integer>();

4. Using Object Carefully: If Java generics are not an option, use Object cautiously and perform explicit type checks.

These alternatives to raw types ensure compile-time type safety, prevent runtime errors, and make code more maintainable.

How to Suppress Warnings from Raw Type Usage in Java?

The warning generated by the raw type can be suppressed using @SuppressWarnings. It hides the warnings generated by the raw types. They are used when you do not use Java generics.

Example:

Java

Output:

How to Suppress Warnings Due to Raw Type Usage

Explanation: In the above Java code, the array list is declared without any type parameter defined in it. The warnings generated by the raw types are hidden by the @SuppressWarnings.

How Raw Types in Java Cause Heap Pollution?

Heap pollution occurs when a variable of type X doesn’t reference X or its subclass; instead, it references Y, where X and Y both have different types.

Raw types can cause heap pollution because the generic type information is removed at compile time, which allows operations that violate type safety.

Example:

Java

Output:

How does Raw Type cause Heap Pollution

Explanation: In the above Java code, the ArrayList is declared as a raw type. The ClassCastException will occur when the program attempts to retrieve and cast the element to String, not at insertion.

Comparing Raw Types with Unbounded Wildcards (<?>)

Feature Raw Type (List) Unbounded Wildcard (List<?>)
Type Safety Not enforced Enforced at compile time
Compiler Warnings Generates unchecked warnings No warnings (if used correctly)
Read Operations Allowed (returns Object) Allowed (returns Object)
Write Operations Allowed (unsafe) Not allowed (except null)
Use Case Legacy compatibility Safe read-only access when type is unknown
Type Information Retained No Yes (generic context preserved)
Recommended in Modern Java No Yes (for unknown generic types)

Why Non-Static Members in Raw Types Are Also Raw in Java?

In Java, when a generic class is used as a raw type, all its non-static type members are also considered raw due to type erasure. Type erasure removes generic type parameters at compile time, treating them as Object, which leads to a loss of type safety.

When a raw type is used, the compiler does not enforce type checking on its non-static members, making them behave as if they were declared with Object.

1. Type Erasure Removes Generic Type Information

  • All generic type information is erased at runtime, and type parameters are replaced with Object.

2. Non-Static Fields Depend on Type Parameters

  • In a generic class, non-static fields store the data of type T.
  • When the class is used as a raw type, T is converted to an Object, which leads to heap pollution.

3. Non-Static Methods Operate on Raw Types

  • If a method in a raw type is used to return a generic type, it will return an Object. This has to be explicitly cast, which can increase the risk of a ClassCastException.

Get 100% Hike!

Master Most in Demand Skills Now!

Conclusion

Raw types in Java were used before Java 5, but are not so safe to use now. They can cause errors at runtime, warnings, and mixing of different data types, which can lead to problems. Non-static members are also considered raw types because Java removes type information at runtime. To keep your code safe and clear, you should always use generic types instead of raw types.

To learn more about this topic, you can refer to our Java Course and also check out the Java Interview Questions prepared by industry experts.

Raw Types in Java – FAQs

Q1. What are raw types in Java?

A raw type is the name of a generic class or interface without any type arguments.

Q2. What is a potential drawback of using raw types in generic programming?

One of the major drawbacks is the lack of type safety. The compiler cannot perform type checks when using raw types. This leads to potential runtime errors.  

Q3. Why do we use only String args in Java?

String arguments in Java are used to pass command-line arguments to a Java program.

Q4. Can using raw types lead to exceptions at runtime?

Using raw types can lead to exceptions at runtime, so don’t use them.

Q5. Why are generics safe in Java?

Because it provides stronger type checks at compile time

Q6. What are Disadvantages of raw types in Java?

Raw types in Java lack type safety, leading to potential ClassCastException at runtime, and generate unchecked warnings, making code harder to maintain.

Q7. What are advantages of raw types in Java?

Raw types in Java provide backward compatibility with legacy code written before generics were introduced. They allow interaction with non-generic APIs and simplify code when type safety is not a concern.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.

Full Stack Developer Course Banner