|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 8 of 9
north
south
east
west
98
63
87
Now say you want to copy a list of objects to another list subject to a filter. You might consider declaring a void copy(List<Object> src, List<Object> dst, Filter filter) method, but this method would only be able to copy Lists of Objects and nothing else.
To pass source and destination lists of arbitrary type, you need to use the wildcard for a type placeholder. For example,
consider the following copy() method:
void copy(List<?> src, List<?> dest, Filter filter)
{
for (int i = 0; i < src.size(); i++)
if (filter.accept(src.get(i)))
dest.add(src.get(i));
}
This method's parameter list is correct, but there's a problem. According to the compiler, dest.add(src.get(i)); violates type safety. The ? implies that any kind of object can be the list's element type, and it's possible that the source and destination element
types are incompatible.
For example, if the source list was a List of Shape and the destination list was a List of String, and copy() was allowed to proceed, ClassCastException would be thrown when attempting to retrieve the destination list's elements.
You could partially solve this problem by providing upper and lower bounds for the wildcards, as follows:
void copy(List<? extends String> src, List<? super String> dest,
Filter filter)
{
for (int i = 0; i < src.size(); i++)
if (filter.accept(src.get(i)))
dest.add(src.get(i));
}
You can provide an upper bound for a wildcard by specifying extends followed by a type name. Similarly, you can supply a lower bound for a wildcard by specifying super followed by a type name. These bounds limit the types that can be passed as actual type arguments.
In the example, you can interpret ? extends String as any actual type argument that happens to be String or a subclass. Similarly, you can interpret ? super String as any actual type argument that happens to be String or a superclass. Because String is final, which means that it cannot be extended, only source lists of String objects and destination lists of String or Object objects can be passed, which isn't very useful.
You can fully solve this problem by using a generic method, which is a class or instance method with a type-generalized implementation. A generic method declaration adheres to the following syntax:
<formalTypeParameterList> returnType
identifier(parameterList)
A generic method's formal type parameter list precedes its return type. It consists of type parameters and optional upper bounds. A type parameter can be used as the return type and can appear in the parameter list.
Listing 9 demonstrates how to declare and invoke a generic copy() method.
import java.util.ArrayList;
import java.util.List;
public class GenDemo
{
public static void main(String[] args)
{
List<Integer> grades = new ArrayList<Integer>();
Integer[] gradeValues =
{
new Integer(96),
new Integer(95),
new Integer(27),
new Integer(100),
new Integer(43),
new Integer(68)
};
for (int i = 0; i < gradeValues.length; i++)
grades.add(gradeValues[i]);
List<Integer> failedGrades = new ArrayList<Integer>();
copy(grades, failedGrades, new Filter<Integer>()
{
public boolean accept(Integer grade)
{
return grade.intValue() <= 50;
}
});
for (int i = 0; i < failedGrades.size(); i++)
System.out.println(failedGrades.get(i));
}
static <T> void copy(List<T> src, List<T> dest,
Filter<T> filter)
{
for (int i = 0; i < src.size(); i++)
if (filter.accept(src.get(i)))
dest.add(src.get(i));
}
}
interface Filter<T>
{
boolean accept(T o);
}
In Listing 9 I've declared a <T> void copy(List<T> src, List<T> dest, Filter<T> filter) generic method. The compiler notes that the type of each of the src, dest, and filter parameters includes the type parameter T. This means that the same actual type argument must be passed during a method invocation, and the compiler infers this argument
by examining the invocation.
If you compile Listing 9 (javac GenDemo.java) and run the application (java GenDemo) you should observe the following output:
java.util.concurrent.
java.time classes you're most likely to need.