Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

Question about returning generics

Thread view: 
aaronfude@gmail.com - 04 Feb 2007 19:24 GMT
Hi,

Suppose I have an array of diverse types and I want extract all
objects of a certain type (e.g. Date) and return it as a vector of
that type. Is it possible to write a function that will return arrays
of different types depending on the input parameters. I guess I have
just about answered my own question negatively, but I'm hoping for
something like this:

Vector<Date> dates = collect(set, Date.class);
Vector<Double> doubles = collect(set, Double.class);

Not possible, right?

Thanks!

Aaron Fude
Tom Hawtin - 04 Feb 2007 20:03 GMT
> Suppose I have an array of diverse types and I want extract all
> objects of a certain type (e.g. Date) and return it as a vector of
[quoted text clipped - 5 lines]
> Vector<Date> dates = collect(set, Date.class);
> Vector<Double> doubles = collect(set, Double.class);

Arrays or Vectors.

> Not possible, right?

I don't see why it should be impossible.

public static <T> List<T> collect(
    Iterable<?> items, Class<? extends T> target
) {
    if (target.isPrimitive()) {
        throw new IllegalArgumentException();
    }
    List<T> found = new java.util.ArrayList<T>();
    for (Object item : items) {
        if (target.isInstance(item)) {
            found.add(item);
        }
    }
    return found;
}

@SuppressWarnings("unchecked")
public static <T> T[] collect(
    Iterable<?> items, Class<T> target
) {
    List<T> found = collect(items, target);
    return found.toArray((T[])
        java.lang.reflect.Arrays.newInstance(target, found.size())
    );
}

[Disclaimer: Not tested, or even compiled.]

I am not, however, convinced that this is a brilliant design.

Tom Hawtin
Mike Schilling - 04 Feb 2007 20:14 GMT
> Hi,
>
[quoted text clipped - 7 lines]
> Vector<Date> dates = collect(set, Date.class);
> Vector<Double> doubles = collect(set, Double.class);

You want something like

   static <T> Vector<T> collect(Collection c, Class<T> clazz)
   {
       Vector<T> v = new Vector<T>();
       for (Object o : c)
       {
           if (clazz.isInstance(o))
               v.add((T) o);
       }
       return v;
  }

Class<T> is an idiom worth learning.  The only member (other than null) of
the type Class<T> is T.class.  If you're writing generic code and will need
access to the Class object for a parameterized type, having an argument of
type Class<T> is the way to get it.

Warning: I've compiled this but not tested it, so beware of subtle bugs.
Note also that isInstance() returns false for null arguments (like
instanceof does), so you'll never see null members in the Vector.
Chris Uppal - 04 Feb 2007 20:16 GMT
> Suppose I have an array of diverse types and I want extract all
> objects of a certain type (e.g. Date) and return it as a vector of
> that type. Is it possible to write a function that will return arrays
> of different types depending on the input parameters.

Probably not a good idea to design your API in terms of raw arrays, nor to use
Vector (essentially obsolete, and has been for many years).  But using
java.util.List it seems to work OK:

   -- chris

======== Utils.java ============
import java.util.*;

public class Utils
{
   public static <X>
   List<X>
   collect(List<Object> list, Class<X> clobj, boolean allowNull)
   {
       List<X> filtered = new ArrayList<X>();
       for (Object elem : list)
       {
           if (allowNull && elem == null)
               filtered.add(null);
           else if (clobj.isInstance(elem))
               filtered.add(clobj.cast(elem));
       }
       return filtered;
   }
}
======== Test.java ============
import java.util.*;

public class Test
{
   public static void
   main(String[] args)
   {
       List<Object> all = Arrays.asList(new Object[] {
                               "one",
                               null,
                               true,
                               false,
                               'c',
                               88.88,
                               100
                            });

       System.out.println("Strings (or null):");
       List<String> strings = Utils.collect(all, String.class, true);
       for (String s : strings)
           System.out.println("\t" + s);

       System.out.println("Numbers:");
       List<Number> numbers = Utils.collect(all, Number.class, false);
       for (Number n : numbers)
           System.out.println("\t" + n);
   }
}
=============================
Chris Uppal - 04 Feb 2007 20:34 GMT
I wrote:

>     public static <X>
>     List<X>
>     collect(List<Object> list, Class<X> clobj, boolean allowNull)
>     {

Come to think of it (and influenced in part by Tom's post), I think that:

   public static <Super, Sub extends Super>
   List<Sub>
   collect(
       List<? extends Super> list,
       Class<Sub> clobj,
       boolean allowNull)
   {
       List<Sub> filtered = new ArrayList<Sub>();
       for (Super elem : list)
       {
           if (allowNull && elem == null)
               filtered.add(null);
           else if (clobj.isInstance(elem))
               filtered.add(clobj.cast(elem));
       }
       return filtered;
   }

is to be prefered.

Notice how the attempt to satisfy the compiler results in reams of code, no
real gain, and a distraction of attention from /non/ inessentials such as the
hardwired decision that the returned List as an ArrayList.

   -- chris
Tom Hawtin - 04 Feb 2007 21:14 GMT
> I wrote:
>
[quoted text clipped - 12 lines]
>         boolean allowNull)
>     {

> is to be prefered.

I certainly wouldn't want to insist on a List of Object. I'm not sure
what the point of 'Super' is there. Most code will not specify type
arguments for generic methods explicitly (wish the same was true for
types in constructors). Object will always be sufficient for 'Super'.

I don't like the allowNull parameter. I don't see what the point of
using it would be. The code would be simpler without it. And the calling
code would be more understandable without a strange boolean flag tagged
onto the end without explanation.

Also generic parameters. Can we have them in AOL? I spent ages the other
day trying to find where a pair of classes/interfaces were defined.
NetBeans just shrugged. Then I realised what they were. (OTOH, I
sometimes like multiple characters - EXC for exceptions and THIS for
self type).

> Notice how the attempt to satisfy the compiler results in reams of code, no
> real gain, and a distraction of attention from /non/ inessentials such as the
> hardwired decision that the returned List as an ArrayList.

Yes, but at least it is the method author who has to worry about it. And
hopefully the method will be used more often than it is implemented. A
programmer using the method doesn't need to concern his or herself about
it. Just see that it has been worked out, and the compiler will note any
misunderstanding.

Tom Hawtin


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.