There is a program which handles many lists of many types (Person, Cat, Chairs etc..).
The following code appears many times in the code. The code fills a given list with instances of type Cat until the list has a given number of instances.
int howMany = max - cats.size();
for(int i = 0; i < howMany; ++i) {
cats.add(new Cat());
}
Since this code appears many time we want to create a method to replace it. The method will accept the List that we want to add instances to and the max number of instances. It can accept more parameters if needed.
This seems simple at first but then I remembered it's not possible to write new T() because of type erasure.
What other way is there to achieve this?
You can re-use a method, that instantiates a class of a given type T.
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
Then, you can implement a method, that populates a given List<T> with n objects of type T.
public <T> void populateList(List<T> list, Class<T> clazz, int n) {
for (int i = 0; i < n; i++) {
list.add(getInstanceOfT(clazz));
}
}
Note1: You have to handle IllegalAccessException and InstatiationException.
Note2: If you don't want to use getInstanceOfT() you can just do clazz.newInstance() when adding to the list.
You can use the method as follows:
int howMany = max - cats.size();
Class<Cat> catClass = Cat.class;
List<Cat> listOfCats = new ArrayList<Cat>();
populateList(listOfCats, Cats.class, howMany);
More info:
Create instance of Generic type in Java
Instead of adding all those unnecessary objects to the list, couldn't you wrap the shorter lists in an object that makes them look longer?
class PaddedList<T> extends AbstractList<T> implements List<T> {
private final List<T> wrappedList;
private final int size;
private final T padding;
public PaddedList(List<T> wrap, int size, T pad) {
this.wrappedList = wrap;
this.size = size;
this.padding = pad;
}
#Override
public T get(int index) {
return index < wrappedList.size() ? wrappedList.get(index) : padding;
}
#Override
public int size() {
return size;
}
}
public void test() {
List<String> test = Arrays.asList("One", "Two");
List<String> list10 = new PaddedList<>(test, 10, "Many");
System.out.println(list10);
}
this prints
[One, Two, Many, Many, Many, Many, Many, Many, Many, Many]
Obviously this will go very wrong if you try to modify any of the objects that are used as padding but if all you want is your lists seeming like they are fixed length then this would work very efficiently.
Related
I am trying to implement a basic hashmap in Java and am stuck on why I cannot declare an array of my custom class KVPair. I am getting an error after numerous trials of fixing my declaration of the array in my constructor:
contains = new KVPair[capacity];
When I tried this, I got a compile error saying that I "cannot create a generic array of HashMap.KVPair."
I have also seen from another stackexchange answer that suggested casting an array of objects into something else like this:
contains = (KVPair[])new Object[capacity];
When I do this, I get a run-time error saying "java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [MyHashMap$KVPair;."
Below I have included one of the constructors of my hashmap class as well as my KVPair class. Any help on how I can solve this issue would be much appreciated.
public class MyHashMap<K, V> implements Iterable<K> {
private static final int DEFAULT_CAPACITY = 200;
private static final double DEFAULT_LOAD_FACTOR = 0.7;
private int capacity; // the number of buckets in the map
private int size; // the number of items that have been put into the map
private double loadFactor;
KVPair[] contains;
// Constructs an empty map.
public MyHashMap() {
capacity = DEFAULT_CAPACITY;
this.loadFactor = DEFAULT_LOAD_FACTOR;
contains = (KVPair[]) new Object[capacity];
}
...
public class KVPair {
private K key;
private V value;
private KVPair next;
private int hash;
private KVPair(Object k, Object v){
key = (K) k;
value = (V) v;
next = null;
hash = k.hashCode();
}
public KVPair(Object k, Object v, KVPair nextKV){
key = (K) k;
value = (V) v;
next = nextKV;
hash = k.hashCode();
}
}
Usually implementations of collections that require an underlying generic array solve this problem by using a non-generic array of type Object[]. As long as the array is hidden as an implementation detail and that the method exposed by the collection are all generic, then it is completely type-safe to do so. You can see that in the JDK code in particular (for example: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/ArrayList.java#ArrayList).
Another solution for instantiating generic arrays is to use Array.newInstance. However, this requires to pass the class of the generic type, which you most likely don't want to impose on the user of your API. Just for the record, here is as this can be used to create a generic array factory method:
public class ArrayUtils {
#SuppressWarnings("unchecked")
public static <T> T[] ofDim(Class<T> clazz, int length, T defaultValue) {
T[] arr = (T[]) Array.newInstance(clazz, length);
for (int i = 0; i < length; i++) arr[i] = defaultValue;
return arr;
}
}
In short:
if your generic array can be hidden as an implementation detail, use a bare Object[]
if your generic array is going to be passed and potentially mutated by an external class, you need to ensure runtime type safety using Array.newInstance
I've got a method which goes like this -
public IntSequence subSequence(int index, int size) {
//IntSequence is an interface and currently this thing is inside a class that's
//implementing it
ArrayList<Integer> valuelist = new ArrayList<>();
for(int i = a1; i <= a2 + a1; i++)
{
if((a1 + a2) <= a.length)
valuelist.add(a[i]);
}
return valuelist;
}
My problem here is, I just want to return a sequence of integers however what I am returning here is an ArrayList and the compiler says cannot convert from type IntSequence to ArrayList.
(I'm not allowed to change the parameters of the method)
Thanks for acknowledging the problem!
EDIT :
This is my IntSequence interface -
public interface IntSequence {
int length();
int get(int index);
void set(int index, int value);
IntSequence subSequence(int index, int size);
}
Without seeing IntSequence, it's hard to give a specific answer. But you probably want to do something like:
class ArrayIntSequence implements IntSequence {
private ArrayList<Integer> arr;
public ArrayIntSequence (ArrayList<Integer> arr) {
this.arr = arr;
}
public ...
// provide bodies for all the methods defined in IntSequence, implemented
// using "arr"
}
and then your return statement in subSequence becomes
return new ArrayIntSequence(valuelist);
EDIT: now that you've included the definition of IntSequence, the implementation of length, get, and set are very simple using the similar ArrayList methods, and it looks like you've already got subSequence except that you can tweak it to use an ArrayList instead of an array.
Try this:
public IntSequence subSequence(int index, int size) {
// ...
final ArrayList<Integer> valuelist = new ArrayList<>();
// ...
return new IntSequence() {
// Compiler will tell you what to put here
};
}
The compiler will give you some errors, telling you what methods you need to implement in order to return an IntSequence. If this is too much you might want to create a new object of the class that implements the interface and see if you can pass just the right contents to a constructor.
Your method implements a method that returns IntSequence. If you try to return an ArrayList<Integer> instead, you are not actually fulfilling the interface. You will need to convert the ArrayList to whatever IntSequence is and return that.
So guys I have to write a generic method to find the maximum element in a 2-D array then I have to test using integers, strings, and objects.
I'm a little sleep deprived so I apologize for what is probably a very very simple fix.
I have my generic method:
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (int i = 0; i < stuff.length; i++)
for(int j = 0; j <stuff.length; i++)
if (stuff[i][j].compareTo(max) > 0)
max = stuff[i][j];
return max;
}
}
and simply trying to test with integers first
public class GenericTester {
public static void main(String[] args) {
Integer[][] myArray = { {0,1,2,3}, {3,2,1,0}, {3,5,6,1}, {3,8,3,4} };
System.out.println(Generic.Max(myArray));
}
}
Ok I fixed the previous error, dumb mistake, but yes now I am getting The method Max(T[][]) in the type Generic is not applicable for the arguments (int[][])
what would be the best fix for this problem?
Thanks for any and all help
Presumably you need Generic.Max(myArray) or else you need to
import static Generic.Max;
at the top of GenericTester.java.
Generics will not work with primitive types, so T cannot be bound to int. Note, in particular, that int does not extend Comparable<int>. You will need to use an Integer[][] array instead of int and similarly for the other primitive types.
EDIT In addition to the above, your loops need some work. First, the increment on the inner loop is wrong (this is why you are seeing an ArrayIndexOutOfBoundsException). Second, your code requires that the matrix is square and full (since you use stuff.length for the inner loop limit). Here's how I would write them (using enhanced for loop syntax):
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (T[] row : stuff) {
for (T elt : row) {
if (elt.compareTo(max) > 0) {
max = elt;
}
}
}
return max;
}
}
For a truly general method, you would want to check that stuff[0][0] exists.
Hello fellow Stackoverflowers,
I have the following problem:
I have a situation, where I get an array of primitive numbers as an input. For example int[] or short[] or even byte[]. Now, I need to iterate over the code and do certain stuff, for example, write the numbers into a list. The problem is, however, that every type of number needs a certain list. No problem, I thought, and tried to use generics:
Object dataSet = provider.getDataArray();
Number[] copy = new Number[Array.getLength(dataSet)];
for(int i= 0; i < Array.getLength(dataSet); i++) {
copy[i] = (T) Array.get(dataSet, i);
}
This works beautifully. However, the problem is with performance. I know that is cannot be circumvented because Reflection and the occuring boxing of the primitives is costly. I am now searching for a pattern to reduce the amount of code, because writing
Object dataSet = provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();
Number[] copy = new Number[dataSet.length];
if(dataType == Float.class)
float[] dataSetAsFloat = (float[]) dataSet;
for(int i= 0; i < dataSet.length; i++)
copySet[i] = dataSetAsFloat[i];
else if (dataType == Double.class)
double[] dataSetAsDouble = (double[]) dataSet;
for(int i= 0; i < dataSet.length; i++)
copySet[i] = dataSetAsFloat[i];
....
is a very bloated solution, because the application in the program I'm writing is not as simple as shown here. Basically, I create several hundred lines of extra code because of this performance problem. Is there a solution to this? Perhaps a pattern I'm not aware of, or some really simple trick I'm not seeing?
I would be immensely grateful for a response.
Thanks.
Have you considered a strategy pattern that chooses a conversion strategy based on the data type? While it won't reduce much of the overall total code, it will help to modularize it.
public interface ArrayConversionStrategy<T extends Number> {
T[] convertArray
}
public class FloatConversionStrategy implements ArrayConversionStrategy<Float>
float[] convertArray(Object[] dataset) {
float[] dataSetAsFloat = new float[dataset.length];
for(int i= 0; i < dataSet.length; i++)
dataSetAsFloat [i] = dataset[i];
}
}
public class DoubleConversionStrategy { ... }
public class LongConversionStrategy { ... }
Then in the calling class have a map of data types to strategies
Map<Class<? extends Number>, ArrayConversionStrategy> map;
Object[] dataSet = provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();
ArrayConversionStrategy strategy = map.get(dataType)
return strategy.convertArray(dataSet);
Some of my generic syntax may be off here and may have some boxing/autounboxing that may need to be done, but just as a general strategy this may be useful.
Instead of unpacking the wrapper, you can use a getLong(int)/putLong for integers and getDouble(int)/putDouble for floating point. This will give you two methods which support all primitives types.
interface Array {
public long getLong(int idx);
public double getDouble(int idx);
public void setLong(int idx, long l);
public void setDouble(int idx, double d);
}
class ByteProvider implements Array {
}
class IntProvider implement Array {
etc.
I have to pass a primitive 2d array to a filtering routine.The algorithm for filtering(median filter) is same irrespective of the type of the array.Is there a way to pass any type of array in a generic manner or should I overload the same same function with different array types.In the second case the same code will have to be repeated for different data types.
int[][] medianfilter(int[][] arr){ ... }
float[][] medianfilter(float[][] arr){ ... }
Is there a way to make the above code a generic one,instead of repeating the code for medianfilter in each an every overloaded function ?
There is no good way to do this for primitive arrays, which is why all the library functions (such as java.util.Arrays) also have these duplicated methods.
You could define a method
Object[] medianfilter(Object[] arr); // note the missing dimension
and use reflection to find out the runtime type. This is what System.arraycopy is doing. But you then need to type-cast. Ugly.
int[][] result = (int[][]) medianFilter( input );
Go with the duplicated methods.
There is a way to pass the type of an array in a generic manner:
public T test(T[][] arg)
{
T[][] q = arg;
T[] r = q[0];
T s = r[0];
return s;
}
... unfortunately it won't work for primitive types. You'll need to use Integer and Float as your parameterized types.
The only way to pass it in a generic manner and keep it as a primitive array is as an Object. Personally, I'd just overload it, and see it as a cost of using primitives.
To avoid duplication of code in the algorithm (if it is a lot of code) you could produce an abstract class called something like DoubleAlgorithm with abstract methods like double getElement(int i, int j) and handleResult(double result) and then write very small subclasses of this, one for each primitive type.
Let me explain with an example (suppose the algorithm was adding the numbers).
public int filter(int [][] values) {
IntAlgorithm algo = new IntAlgorithm(values);
algo.run();
return algo.getResult();
}
public double filter(double [][] values) {
DoubleAlgorithm algo = new DoubleAlgorithm(values);
algo.run();
return algo.getResult();
}
public class AbstractAlgorithm {
public run() {
double sum = 0.0;
for(int i=0; i<rows(); i++) {
for(int j=0; j<columns(i); j++) {
sum+=getElement(i, j);
}
}
handleResult(sum);
}
protected abstract int rows();
protected abstract int columns(int row);
protected abstract double getElement(int i, int j);
protected abstract void handleResult();
}
public class IntAlgorithm extends AbstractAlgorithm {
int [][] values;
int result;
IntAlgorithm(int [][] values) {
this.values= values;
}
public int rows() {
return values.length;
}
public int columns(int row) {
return values[row].length;
}
public double getElement(int i, int j) {
return values[i][j];
}
public void handleResult(double result) {
this.result = (int)result;
}
public int getResult() {
return result;
}
}
As you can see, it is quite verbose, but if your algorithm was big it might be worth it. Hopefully it is obvious how to extend to your algorithm.
As Thilo has pointed out, it isn't safe to do all algorithms with just treating ints/longs as doubles, but for a number it will be good enough. If it isn't for you, then you need to go even more verbose, work out which properties of numbers you need (eg add) and extract those to a separate interface. For a median filter, I would expect just using doubles will work fine, but I'd test the edge cases.