Question about returning generics

A

aaronfude

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
 
T

Tom Hawtin

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);

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
 
M

Mike Schilling

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);


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.
 
C

Chris Uppal

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);
}
}
=============================
 
C

Chris Uppal

I said:
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
 
T

Tom Hawtin

Chris said:
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)
{
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,481
Members
44,900
Latest member
Nell636132

Latest Threads

Top