Generics - Confusion - java

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

Related

Create random values of generic type in Java

I have the following:
public class RandomList {
private List<Integer> list;
public List<Integer> getList() {
return list;
}
public RandomList (int n) {
list = new ArrayList<Integer>();
Random rand = new Random();
rand.setSeed(System.currentTimeMillis());
for (int i=0; i < n; i++)
{
Integer r = rand.nextInt();
list.add(r);
}
}
}
which gives me a list filled with random Integer values. I would like to generalize this, to also get a list of random Character values or perhaps lists of other types' random values.
So what I want is a generic type version, class RandomList<T>. I can replace everywhere "Integer" by "T", but am stuck at the line Integer r = rand.nextInt(); which would read different for different types.
I am thinking of doing the following:
pass in the class of the generic type to RandomList
using instanceof check the passed in class against the desired types (Integer, Character...) and depending on the check return the proper random value
Does this make sense? Is there another/better way to achieve what I want?
First method (inferior)
In Java you can't check for the generic type, at least not without reflection. You're on the money with the generic type, so you'd do something like this:
public class RandomList<T> {
private List<T> list;
private Class<T> clazz;
public List<T> getList() {
return list;
}
public RandomList (Class<T> clazz, int n) {
this.clazz = clazz;
list = new ArrayList<T>();
Random rand = new Random();
rand.setSeed(System.currentTimeMillis());
if (clazz.isAssignableFrom(Integer.class)) {
for (int i = 0; i < n; i++) {
Integer r = rand.nextInt();
list.add(r);
}
}
else {
throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
}
}
}
Second method (superior)
Alternatively, you could generalise this even further and add a Function to produce the randomised results. Note that this requires Java 8. If you're not on Java 8, you could just define an interface and construct that anonymously.
public class RandomList<T> {
private List<T> list;
public List<T> getList() {
return list;
}
public RandomList (Function<Random, T> creator, int n) {
list = new ArrayList<T>();
Random rand = new Random();
rand.setSeed(System.currentTimeMillis());
for (int i = 0; i < n; i++) {
list.add(creator.apply(rand));
}
}
}
Construct a new instance using:
RandomList<Integer> list = new RandomList<>(rand -> rand.nextInt(), 10);
Third method (cleaner)
Edit: This occurred to me later, but you seem to be using Java 8, so you could just use streams:
List<Integer> list = Stream.generate(() -> rand.nextInt()).limit(10).collect(Collectors.toList())

Working with an ArrayList of Functions in Java-8

Problem Description:
I want to be able to use an ArrayList of Functions passed in from another class (where the Functions have been defined in that other class). If the list of Functions, which may have different input and return types, are defined in one class, I want to be able to pass an ArrayList of some of them, with possible duplicates, as a parameter to some other class's constructor or method and perform operations using them.
Code Description:
The code below is a greatly simplified example which is not intended to make much sense from a design perspective. The focus of the problem is the method getResult() within SomeClass and generally how to use an ArrayList of Functions once you have them.
Attempt to solve the problem:
The getResult() method implementation is an example of one of many attempts to use the Function list. Again, please don't mind the design of the code. It was just done that way to try to make the problem example as short as possible.
Simple tester class
package com.Testing;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
public class Tester {
public static void main(String[] args)
{
// Some functions
Function<Integer, Integer> increment = (Integer input) -> {
return input + 1;
};
Function<Integer, Integer> decrement = (Integer input) -> {
return input - 1;
};
Function<Double, Double> timesPi = (Double input) -> {
return input * 3.14;
};
// list of Functions
List<Function> availableMathOperations = new ArrayList<>();
List<Function> selectedMathOperations = new ArrayList<>();
// populate master list
availableMathOperations.add(increment);
availableMathOperations.add(decrement);
availableMathOperations.add(timesPi);
// Populate random selection list //
// generate random binary number
Random randomGenerator = new Random();
int randomNumber = randomGenerator.nextInt(availableMathOperations.size() * 2);
boolean[] bits = new boolean[availableMathOperations.size()];
for (int j = 0; j < availableMathOperations.size(); j++) {
bits[availableMathOperations.size() - 1 - j] = (1 << j & randomNumber) != 0;
}
// add math operations to selectedMathOperations based on binary number
for (int j = 0; j < bits.length; j++) {
if (bits[j]){
selectedMathOperations.add(availableMathOperations.get(j));
}
}
SomeClass someClass = new SomeClass(selectedMathOperations, 1.23);
}
}
Other class
package com.Testing;
import java.util.List;
import java.util.function.Function;
public class SomeClass {
List<Function> operations;
double initialValue;
public SomeClass(List<Function> newOperations, double newInitialValue){
operations = newOperations;
initialValue = newInitialValue;
}
public double getResult(){
double result = 0.0;
// problem method
// perform the random list of operations using the initial value initially
for(int i = 0; i < operations.size(); i++){
if(i == 0)
result = operations.get(i)(initialValue);
else
result += operations.get(i)(result);
}
return result;
}
}
The method of a java.util.function.Function object is apply. You need to call it like this:
operations.get(i).apply(initialValue)
However you use raw Function and therefore the result could be Object and you'd need to convert it to the appropriate type. Also you can't use the + (or the +=) operator with it. I'd suggest restricting the parameter types with Number:
List<Function<Number, ? extends Number>> operations = Arrays.asList(
num -> num.intValue() + 1,
num -> num.intValue() - 1,
num -> num.doubleValue() * 3.14
); // just an example list here
public double getResult() {
double result = 0.0;
for (int i = 0; i < operations.size(); i++) {
if (i == 0) {
result = operations.get(i).apply(initialValue).doubleValue();
} else {
result += operations.get(i).apply(result).doubleValue();
}
}
return result;
}
I'm not convinced I understand correctly, but I think the problem you're facing is how to call the functions in your List? The JavaDoc for the Function interface states that it has a single non-abstract method, apply() that you call to use the Function, as follows:
public double getResult(){
double result = 0.0;
for(int i = 0; i < operations.size(); i++){
if(i == 0)
result = operations.get(i).apply(initialValue);
else
result += operations.get(i).apply(result);
}
return result;
}
As an aside, that method could be tidied up a bit to make it simpler:
public double getResult() {
double result = initialValue;
//Not sure if this if-statement is a requirement, but it is to replicate
//the functionality in the question
if (operations.isEmpty()) {
return 0.0;
}
for (Operation operation : operations) {
result = operation.apply(result);
}
return result;
}
And as others have said in the comments, you should use generics when passing around your List objects (I guess you'll have to use something like List<Function<? extends Number, ? extends Number>)

Deduplicate this java code duplication

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

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.

Java: Integer obj can't cast to Comparable

I'm having problems trying to pass an Integer object from a driver class as an argument for function of a SortedArray Generic class I created. From my driver class, I convert the user's int input into an Integer object to be cast onto Comparable of my SortedArray class.
I continue to receive the error: "Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to Comparable". I took a look at some of my classmates' source codes only to find little difference in setting the arguments/parameters yet they have their code working just fine. I've been looking for hours trying to find what error I've made and I still can't find why my Integer object can't be cast to Comparable.
Here's a bit from my SortedArray Class
public class SortedArray implements Comparable{
public int size;
public int increment;
public int top;
Comparable[] a = new Comparable [size];
public SortedArray(int initialSize, int incrementAmount)
{
top = -1;
size = initialSize;
increment = incrementAmount;
}
public int appropriatePosition(Comparable value)
{
int hold = 0;
if(top == -1)
{
return 0;
}
else
{
for(int i = 0; i <= top; i++)
{
if(a[i].compareTo(value) > 0)
{
hold = i;
break;
}
}
}
return hold;
}
public void insert(Comparable value) //The function that my driver class needs to access
{
//Shifting numbers to the top
if(full() == true)
{
Comparable[] tempArray = new Comparable[top + increment];
for(int i= 0; i< size; i++)
{
tempArray[i]= a[i];
a = tempArray;
}
size = top + increment;
}
if(a[appropriatePosition(value) + 1] != null)
{
for(int i = top; i < appropriatePosition(value); i--)
{
a[i + 1] = a[i];
}
}
a[appropriatePosition(value) + 1]= value;
}
Here's the code for my driver class that passes Integer Object insertObj as an argument for SortedArray's insert function.
public class IntDriver {
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
//Creating variables
int data;
boolean check = false;
int choice;
int size = 5;
int increment = 3;
SortedArray b = new SortedArray(size, increment);
//Creating Menu
while(check == false)
{
System.out.println("Please choose through options 1-6.");
System.out.println("1. Insert\n2. Delete\n3. Clear\n4. Smallest\n5. Largest\n6. Exit");
choice = keyboard.nextInt();
switch(choice)
{
case 1:
System.out.println("Type the int data to store in array location.");
data = keyboard.nextInt();
Integer insertObj = new Integer(data);
b.insert(insertObj);// Here's where I lay "insertObj" as an argument for the SortedArray function.
System.out.println("The value " + data + " is inserted");
break;
The problem is that Integer extends java.lang.Comparable, then your Comparable is not a java.lang.Comparable. Look at the error message, your Comparable comes from the default package rather than java.lang:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to Comparable
That is, you can't cast java.lang.Integer to your own class
As mentioned by axtavt, the problem is that you have your own class Comparable. More specifically, what that means is that:
Integer.valueOf(1) instanceof java.util.Comparable == true
Integer.valueOf(1) instanceof Comparable == false
This means that somewhere in your code you have something like:
Object[] a = new Object[] {Integer.valueOf(1);};
Comparable x = (Comparable) a[0];
// or something equivalent, this is likely being passed through layers
// and not being done next to each other like this.
You need to change that to:
Object[] a = new Object[] {Integer.valueOf(1);};
java.util.Comparable x = (java.util.Comparable) a[0];
Even better, you should rename your Comparator class to something that doesn't collide with the standard classes in Java. In general, even though Java has namespacing, you should try to avoid your classes having the same name as the system classes to avoid exactly this kind of confusion.
I haven't put too much effort into this, but wouldn't it just be easier to use a SortedSet implementation (or its child interface NavigableSet) like TreeSet rather than write your own class? That is, unless you wanted duplicate elements...

Categories

Resources