Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can we do with generics in Java to make them look better:

I have this method to transform a List to a Map using one of the properties of the elements of the list:

For short it looks like this:

private Map<String, List<Diagnostic<? extends JavaFileObject>>> toMap( List<Diagnostic<? extends JavaFileObject>> diagnostics ) {
    Map<String, List<Diagnostic<? extends JavaFileObject>>> result = new HashMap<String, List<Diagnostic<? extends JavaFileObject>>>();
    for ( Diagnostic<? extends JavaFileObject> d : diagnostics ) {
        List<Diagnostic<? extends JavaFileObject>> list = null;
        if ( !result.containsKey( d.getCode() ) ) {
            list = new ArrayList<Diagnostic<? extends JavaFileObject>>();
            result.put( d.getCode(), list );
        } else {
            list = result.get( d.getCode() );
        }
        assert list != null;
        list.add( d );
    }
    return result;
}

Yiack!..

I like genercis a lot, I use java prior to them and I don't want to go back to the cast everything era, but when a generic contains as element a generic element it self, things go messy.

I know in Java1.7 we will be able to use the "diamond" operator, but there should be another way.

This is what it would look like in a non-generic version:

private Map toMap( List diagnostics ) { 
    Map result = new HashMap();
    for( Object o  : diagnostics ) {
        Diagnostic d = ( Diagnostic ) o; 
        List list = null;
        if( !result.containsKey( d.getCode() ) ) { 
            list = new ArrayList();
            result.put( d.getCode() , list );
         } else { 
            list = result.get( d.getCode() );
         }
         assert list != null;
         list.add( d );
     }
     return result;
}

Approximately, I didn't try to compile it.

How other languages handle this? C# for instance?, Scala? I liked a lot the way SML or Haskell do handle, but something I think too much magic may hurt ( but this is subjective of course )

Is there a workaround for this?

like image 830
OscarRyz Avatar asked Jul 05 '11 21:07

OscarRyz


1 Answers

You define one type parameter named T. Then you can use T within your generic like this:

private <T extends JavaFileObject> Map<String, List<Diagnostic<T>> toMap(List<Diagnostic<T> diagnostics) {
    Map<String, List<Diagnostic<T>> result = new HashMap<String, List<Diagnostic<T>>();
    for (Diagnostic<T> d : diagnostics ) {
        List<Diagnostic<T>> list = null;
        if ( !result.containsKey(d.getCode())) {
            list = new ArrayList<Diagnostic<T>>();
            result.put( d.getCode(), list );
        } else {
            list = result.get( d.getCode() );
        }
        assert list != null;
        list.add( d );
    }
    return result;
}

Above you will see the type parameter defined as <T extends JavaFileObject> and you reuse T everywhere you need to. This will make it a bit cleaner.

like image 79
Mohamed Mansour Avatar answered Oct 19 '22 04:10

Mohamed Mansour