Deduplicate this java code duplication - java

I have about 10+ classes, and each one has a LUMP_INDEX and SIZE static constant.
I want an array of each of these classes, where the size of the array is calculated using those two constants.
At the moment i have a function for each class to create the array, something along the lines of:
private Plane[] readPlanes()
{
int count = header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE;
Plane[] planes = new Plane[count];
for(int i = 0; i < count; i++)
planes[i] = new Plane();
return planes;
}
private Node[] readNodes()
{
int count = header.lumps[Node.LUMP_INDEX].filelen / Node.SIZE;
Node[] nodes = new Node[count];
for(int i = 0; i < count; i++)
nodes[i] = new Node();
return nodes;
}
private Leaf[] readLeaves()
{
int count = header.lumps[Leaf.LUMP_INDEX].filelen / Leaf.SIZE;
Leaf[] leaves = new Leaf[count];
for(int i = 0; i < count; i++)
leaves[i] = new Leaf();
return leaves;
}
etc.
There are 10 of these functions, and the only differences is the class type, so as you can see, there's a ton of duplication.
Does any one have any ideas on how to avoid this duplication?
Thanks.
(I asked a similar question before, but i guess the way i asked it was a bit off)

Use Java generics. That way, you can just write one generic method and specify a type parameter each time you use it.

Bala's solution is close. You can't access constants from the generic type though, so I'd create a getCount() (or whatever you want to name it) and have each subtype implement it with the appropriate constants.
interface LumpySize<L extends LumpySize> {
int getCount(); // subtypes return the appropriate header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE;
T[] initializeArray();
abstract <T extends LumpySize> static class Base implements LumpySize<T> {
protected T[] initializeArray(Class<T> cls) {
int count = getCount();
T[] lumps = (T[]) Array.newInstance(cls, count);
for(int i = 0; i < count; i++) {
try {
lumps[i] = cls.newInstance();
} catch (Exception e) { // obviously this isn't good practice.
throw new RuntimeException(e);
}
}
return lumps;
}
}
}
class Plane extends LumpySize.Base<Plane> {
public int getCount() {
return header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE; // assuming header is available somewhere
}
public Plane[] initializeArray() { return initializeArray(Plane.class); }
}

Okey doke ... I've tested this to make sure, and I believe it does what you're looking for.
You need an interface:
public interface MyInterface
{
public int getSize();
public int getLumpIndex();
}
Your classes implement that interface:
public class Plane implements MyInterface
{
...
public int getSize()
{
return SIZE;
}
public int getLumpIndex()
{
return LUMP_INDEX;
}
}
In the class that header is an instance of, you have ...
public <E extends MyInterface> E[]
getArray(Class<E> c, MyInterface foo)
{
int count = lumps[foo.getLumpIndex()].filelen / foo.getSize();
E[] myArray = (E[]) Array.newInstance(c, count);
for(int i = 0; i < count; i++)
myArray[i] = c.newInstance();
return myArray;
}
You could call it from say, your Plane class as:
Plane[] p = header.getArray(Plane.class, this);
I think? :) Can someone look at this and see if I'm off?
(EDIT: Becasue I've tested it now - That works)
On an additional note, you could eliminate the getters in each class by making getArray() take the size and index as arguments:
public <E extends MyInterface> E[]
getArray(Class<E> c, int size, int index)
{
int count = lumps[index].filelen / size;
E[] myArray = (E[]) Array.newInstance(c, count);
for(int i = 0; i < count; i++)
myArray[i] = c.newInstance();
return myArray;
}
And call it as:
Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX);
from inside your classes. The interface just becomes empty to provide the generic type and you don't have to define the getter methods.
OR (last edit I promise, but this does give you choices and explains a bit about generics)
Ditch the interface. What this removes is some sanity checking because the method doesn't care what type of object you give it:
public <E> E[]
getArray(Class<E> c, int size, int index)
{
...
Now you don't have to define the interface or implement it, you just call:
Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX);

Use generics, but you'll need to pass in some sort of factory object to construct instances to put in your collection, eg:
public class MyClass {
public <E> E[] getArray(IObjectFactory builder, int index, int size){
ArrayList<E> arrayList = new ArrayList<E>();
int count = header.lumps[index].filelen / size;//wasn'tsure where header was coming from...
for(int i = 0; i< count; i++){
E newInstance = builder.getNewInstance();
arrayList.add(newInstance);
}
return (E[]) arrayList.toArray();
}
}
interface IObjectFactory {
<E> E getNewInstance();
}

Related

How can I use a java interface to calculate the union, intersection, and difference of two sets, all in a default method in the interface?

I am new to java so sorry if this is super basic. I need to make default methods in an interface ISet to allow for the calculation of the union, intersection, and difference of 2 sets created in a class that implements this interface. I know how to calculate all of these but I have no idea how to syntactically do it in the interface since it uses interface objects rather than the data structures in the implementing classes.
The Code:
public interface ISet {
void add(Integer val);
Integer removePos(int pos);
boolean contains(Integer val);
int getSize();
default void union(ISet unionWith) {
//List<Integer>unionSet = new ArrayList<>();
//unionSet.add(unionWith);
//List set = new ArrayList();
//set.addAll(0, unionWith);
//ISet unionSet = this;
// To call in main: this.union(unionWith)
// For my variables it would be mySet.union(mySet2)
//this.getSize();
int size1 = this.getSize();
int size2 = unionWith.getSize();
if(this == unionWith) {
}
//List<Integer> unionList = Arrays.asList(this);
ISet allVals = this.add(Integer val);
for(int i = 0; i < size1 + size2; i++) {
if(!this.contains(Integer.unionWith));
}
}
default void intersect(ISet intWith) {
}
default void difference(ISet diffWith) {
}
}
Sorry for the graveyard I'm just trying every thing I can. Pretty much none of this works except for the size stuff. I know that I'm supposed to use all of the other methods above but I have no idea how to use them in this scenario.
I usually try and figure out things like this by myself but after 3 hours of not being able to union two sets I've realized that I just need to get more informed on how java and interfaces work.
I'll really appreciate any help you guys have to offer!
Maybe you need a methed : Integer get(int pos);
public interface ISet {
void add(Integer val);
Integer get(int pos);
Integer removePos(int pos);
boolean contains(Integer val);
int getSize();
default void union(ISet unionWith) {
for (int i = 0; i < unionWith.getSize(); i++) {
this.add(unionWith.get(i));
}
}
default void intersect(ISet intWith) {
for (int i = getSize() - 1; i >= 0; i--) {
Integer value = get(i);
if (!intWith.contains(value)) {
removePos(i);
}
}
}
default void difference(ISet diffWith) {
for (int i = getSize() - 1; i >= 0; i--) {
Integer value = get(i);
if (diffWith.contains(value)) {
removePos(i);
}
}
}
}

ClassCastException Object cannot be cast to

I don't understand why I get ClassCastException on below code in line:
for(int i = 0; i < k.t.length; i++)
So problem is that in method addElement I make replacing of array elements by objects with type T. In my opinion in array should be objects with type T. And compiler doesn't protest for that.
But in run-time JVM cannot cast despite in array is really objects with type T (in case below String), why JVM cannot use polymorphism?
But when I change the T[] t; to Object[] t;
and remove cast in constructor it run correctly without any errors, why?
public class MyCollection<T> {
T[] t;
MyCollection( int size){
t = (T[]) new Object[size];
}
boolean addElement(T e, int i){
if(i < t.length){
t[i] = e;
return true;
}
return false;
}
public static void main(String[] ss){
MyCollection<String> k = new MyCollection<String>(3);
k.addElement("a",0);
k.addElement("b",1);
k.addElement("c",2);
for(int i = 0; i < k.t.length; i++)
System.out.println(k.t[i]);
//for(String s : (String[])k.t)
// System.out.println(s);
}
}
The problem is that you're casting Object[] to T[], and then you're exposing the underlying array. The only reason this works altogether is because the type erasure of T is Object. But since in our case T is being interpreted as String, when we access the array externally, we're trying to cast it to String[], which is incorrect. In order to avoid this issue, you should make the array private and provide accessor methods to retrieve elements. By doing that, you only cast individual elements to their correct type without making assumptions about the underlying array.
public class MyCollection<T> {
private T[] t;
MyCollection( int size){
t = (T[]) new Object[size];
}
boolean addElement(T e, int i){
if(i < t.length){
t[i] = e;
return true;
}
return false;
}
T getElement(int index) {
return t[index];
}
int getLength() {
return t.length;
}
public static void main(String[] ss){
MyCollection<String> k = new MyCollection<String>(3);
k.addElement("a",0);
k.addElement("b",1);
k.addElement("c",2);
for(int i = 0; i < k.getLength(); i++)
System.out.println(k.getElement(i));
//for(String s : (String[])k.t)
// System.out.println(s);
}
}
Note that Java's Collection interface demonstrates the same behavior. Collection.toArray() returns Object[] regardless of the type of E. The only available workaround is Collection.toArray(T[]), where you're forced to pass an array with a fixed type, which can then be either be populated or copied.
Check again the line of the problem. In my opinion the exception will be thrown because of:
for(String s : (String[])k.t)
You`re trying to cast to String[] here, while the array is defined as Object[]:
t = (T[]) new Object[size];
you can Create a new instance of array using the reflection to avoid ClassCastException
example:
import java.lang.reflect.Array;
public class MyCollection<T> {
T[] t;
MyCollection(Class<T> clazz, int size) {
t = (T[]) Array.newInstance(clazz, size);
}
boolean addElement(T e, int i) {
if (i < t.length - 1) {
t[i] = e;
return true;
}
return false;
}
public static void main(String[] ss) {
MyCollection<String> k = new MyCollection<String>(String.class, 3);
k.addElement("a", 0);
k.addElement("b", 1);
k.addElement("c", 2);
for (int i = 0; i < k.t.length; i++)
System.out.println(k.t[0]);
}
}

Sublist Implementation

I am implementing my own LinkedList class.
For sublist(int a,int b function) method,mycode doesn't work properly.it should return sublist of list according to (a and b indexes)(which i succeed) also after this method if any change is made on sublist also list must be effected(not succeed).for example if i execute
(list.sublist(1,4)).clear :list elements from 1 to 4 should clear also.
My code is:
public List<E> subList(int arg0, int arg1) {
ArrayList<E> ar = new ArrayList<E>();
ListIterator myiter=listIterator(arg0);
int k = arg1 - arg0 + 1;
int i;
for(i = 0; i < k; ++i) {
ar.add((E) myiter.next());
}
List <E> sublist=new GITLinkedList(ar);
return sublist;
}
Why don't you return a class that extends List and overwrites some of the internal methods to trick other classes into thinking its only a subset.
For example, in your sublist method you might do this...
public List<E> subList(int startPosition, int endPosition) {
return new SmallerList(this,startPosition,endPosition);
}
and create a SmallerList class like so...
public class SmallerList extends List {
List parentList = null;
int startPosition = 0;
int endPosition = 0;
public SmallerList(List parentList, int startPosition, int endPosition){
this.parentList = parentList;
this.startPosition = startPosition;
this.endPosition = endPosition;
}
// overwrite some directly to appear smaller
public int size(){
return endPosition-startPosition;
}
// overwrite others to make adjustments to the correct position in the parentList
public void add(int index, Object object){
parentList.add(index+startPosition,object);
}
// overwrite others to only search between startPosition and endPosition
public boolean contains (Object object){
for (int i=startPosition;i<endPosition;i++){
if (parentList.get(i).equals(object)){
return true;
}
}
return false;
}
// etc. for all other methods of List.
}
With this approach, all the methods still act on the underlying parentList, but any queries to SmallerList such as add(), get(), contains(), size(), are all tricked to thinking that they're only working on a smaller List

Generics - Confusion

public <X> X createData(int n)
{
int[] values = new int[n];
Random rand = new Random();
for(int i = 0; i < n; i++)
{
values[i] = rand.nextInt(100);
}
JOptionPane.showMessageDialog(null, values.length);
return (X )values;
}
Hi there, I have cobbled together a small method to return an int array as a generic type (i think?)
The point of this is, I am to call a users method who is going to generate me some data, at which point I then take that data and invoke a method of their selection.
The issue is, when i call this method how can I convert the generic type to its "proper" type so as it invoke the method with this data.
Typically my process will be
1) invoke the user method to get their data(reflection)
2) use this data to invoke their other method(reflection)
Is what I am doing/trying here possible or in the process of making it a generic return type am i ruining everything?
Thanks
If you wan't to return a list then I would do it by defining a Supplier interface,
public interface Supplier<T> extends Serializable {
public T get();
}
Which can be defined as,
public <X> List<X> createData(Supplier<X> datum, Integer length){
List<X> values = new ArrayList<X>();
for(int i = 0; i < length; i++)
{
values.add(datum.get());
}
JOptionPane.showMessageDialog(null, values.size());
return values;
}
and can be used as,
List<Integer> ints = createData(new Supplier<Integer>() {
Random rand = new Random();
#Override
public Integer get() {
return rand.nextInt(100);
}
}, 10);

Generic Arithmetic in Java

I have a filter class wherein the user must declare the type (e.g. Filter<Double>, Filter<Float> etc). The class then implements a moving average filter so objects within the class must be added. My question is how to do this? I'm sorry if the answer is simple but I've muddled myself up by thinking about it too much I think :p.
public abstract class FilterData<T>
{
private final List<T> mFilter;
private T mFilteredValue; // current filtered value
protected Integer mSize = 10;
private T mUnfilteredValue; // current unfiltered value
public FilterData()
{
mFilter = new ArrayList<T>();
}
public FilterData(int size)
{
mSize = size;
mFilter = new ArrayList<T>(mSize);
}
public abstract T add(final T pFirstValue, final T pSecondValue);
#SuppressWarnings("unchecked")
public T filter(T currentVal)
{
T filteredVal;
mUnfilteredValue = currentVal;
push(currentVal);
T totalVal = (T) (new Integer(0));
int numNonZeros = 1;
for (int i = 0; i < mFilter.size(); ++i)
{
if (mFilter.get(i) != (T) (new Integer(0)))
{
++numNonZeros;
T totalValDouble = add(mFilter.get(i), totalVal);
totalVal = totalValDouble;
}
}
Double filteredValDouble = (Double) totalVal / new Double(numNonZeros);
filteredVal = (T) filteredValDouble;
mFilteredValue = filteredVal;
return filteredVal;
}
public T getFilteredValue()
{
return mFilteredValue;
}
public List<T> getFilterStream()
{
return mFilter;
}
public T getUnfilteredValue()
{
return mUnfilteredValue;
}
public void push(T currentVal)
{
mFilter.add(0, currentVal);
if (mFilter.size() > mSize)
mFilter.remove(mFilter.size() - 1);
}
public void resizeFilter(int newSize)
{
if (mSize > newSize)
{
int numItemsToRemove = mSize - newSize;
for (int i = 0; i < numItemsToRemove; ++i)
{
mFilter.remove(mFilter.size() - 1);
}
}
}
}
Am I right to include the abstract Add method and if so, how should I extend the class correctly to cover primitive types (e.g. Float, Double, Integer etc.)
Thanks
Chris
EDIT:
Apologies for being unclear. This is not homework I'm afraid, those days are long behind me. I'm quite new to Java having come from a C++ background (hence the expectation of easy operator overloading). As for the "push" method. I apologise for the add method in there, that is simply add a value to a list, not the variable addition I was referring to (made a note to change the name of my method then!). The class is used to provide an interface to construct a List of a specified length, populate it with variables and obtain an average over the last 'x' frames to iron out any spikes in the data. When a new item is added to the FilterData object, it is added to the beginning of the List and the last object is removed (provided the List has reached the maximum allowed size). So, to provide a continual moving average, I must summate and divide the values in the List.
However, to perform this addition, I will have to find a way to add the objects together. (It is merely a helper class so I want to make it as generic as possible). Does that make it any clearer? (I'm aware the code is very Mickey Mouse but I wanted to make it as clear and simple as possible).
What you're trying to do is create a Queue of Number objects with a fixed size, over which you want to calculate an average. With the trivial situation that you have size = 2 and store two integers 1 & 2 you have an average of 1.5 so its reasonable to set the return type of your filter method to double.
You can then write this code similar to this
public abstract class FilterData<T extends Number> {
private final Queue<T> mFilter = new LinkedList<T>();
protected Integer mSize;
public FilterData() {
this(10);
}
public FilterData(int size) {
mSize = size;
}
public double filter(T currentVal) {
push(currentVal);
double totalVal = 0d;
int numNonZeros = 0;
for (T value : mFilter) {
if (value.doubleValue() != 0) {
++numNonZeros;
totalVal += value.doubleValue();
}
}
return totalVal / numNonZeros;
}
public void push(T currentVal) {
mFilter.add(currentVal);
if (mFilter.size() > mSize)
mFilter.remove();
}
public void resizeFilter(int newSize) {
if (mSize > newSize) {
int numItemsToRemove = mSize - newSize;
for (int i = 0; i < numItemsToRemove; ++i) {
mFilter.remove();
}
}
mSize = newSize;
}
}
You should note that this isn't thread safe.

Categories

Resources