Basic
Basic

Reputation: 26766

Is there any reason to use generics in Java?

Perhaps I'm missing the point but coming from a C# background, I can't see any reason to use Java's generics...

In C# I've got a method which takes a string and deserializes it into an object...

public static Deserialize<T>(string source) {
    // Use reflection to examine T and determine
    // which properties I should be reading from
    // the string. Create an instance of T, 
    // populate the properties and return it
}

which I can call as follows: x.Deserialize<AnyClass>("String representation of AnyClass");

Type erasure seems to make this impossible in Java?

My next most common usage of generics is storing things in lists but since I can't do List<int> and have to box to use List<Integer>, it seems like pointless overhead boxing/unboxing when I could just use int[].

So... Is the only real use for generics to do things like

List<MyClass> MyClassList = new List<MyClass>

and get some compile-time type checking? If so, it seems pretty redundant given that the variable name makes it clear what the type should be (at least as long as I'm using sensible naming conventions).

I can't help but feel I'm missing something...

Upvotes: 6

Views: 11017

Answers (6)

Saurabh
Saurabh

Reputation: 7833

List list = new ArrayList();
list.add("car");
list.add("cycle");
list.add(12);

Here list can contain any object , it can be String,Integer or double, Employee etc
which can cause type safety problem and stops runtime errors at compile time.

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

Here, only string values can be added

Upvotes: 1

Paul Boddington
Paul Boddington

Reputation: 37655

Your Deserialize method is not impossible in Java. You just have to explicitly pass the Class object because it cannot be determined at runtime from the type parameter T.

public static <T> T deserialize(Class<T> clazz, String source) {
    // Use reflection to examine clazz and determine
    // which properties I should be reading from
    // the String. Create an instance of T 
    // (which you can do using clazz.newInstance()), 
    // populate the properties and return it
}

It can be called using deserialize(AnyClass.class, "String representation of AnyClass").

Upvotes: 1

Rockstar
Rockstar

Reputation: 2288

From the Java Docs :

Why Use Generics?

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types.

Code that uses generics has many benefits over non-generic code:

  • Stronger type checks at compile time. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.

  • Elimination of casts. The following code snippet without generics requires casting:

    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);
    

    When re-written to use generics, the code does not require casting:

    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0); // no cast
    
  • Enabling programmers to implement generic algorithms. By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.

Upvotes: 4

marcinj
marcinj

Reputation: 50016

List<MyClass> MyClassList = new ArrayList<MyClass>();

is not equivalent to:

List MyClassList = new ArrayList();

the second one will work on Object type, and you will be allowed to do something stupid like MyClassList.add(new Integer(0));

This is one of the major strengths of generics, or templates in C++. Compile time check that verifies your application that it will not do any undefined behaviour - like in above example.

Upvotes: 0

fge
fge

Reputation: 121780

Well, if you don't use generics, you get to cast each time. You would have to:

// if raw List
MyClass c = (MyClass) myClassList.get(0);
// if List<MyClass>
MyClass c = myClassList.get(0);

for instance.

Yes, generics are erased at runtime, yes, they are here to enforce type safety at compile time only; however there is still runtime type erasure when you use bounds. Example:

public <E extends RuntimeException> E get(final Class<E> c,
    final Throwable t)
{
    try {
        return (E) getHandle(c).invokeExact(t);
    } catch (Error | RuntimeException e) {
        throw e;
    } catch (Throwable oops) {
        final RuntimeException exception = new IllegalStateException(oops);
        exception.addSuppressed(t);
        throw exception;
    }
}

The E here has a runtime type erasure; it extends RuntimeException. Therefore the cast is to RuntimeException, not Object.

See the javadoc of Collections.max() for another interesting example of runtime type erasure (hint: why does it define T extends Object & Comparable<? super T> instead of T extends Comparable<? super T>?)

Upvotes: 11

hasan
hasan

Reputation: 1114

Generic Types are checked in compile time only but it can be helpful to avoid bugs.

Upvotes: 1

Related Questions