I'm trying to create a custom class the creates matrices and, among other things, performs operations that add up all of the cells or multiply them all. However, I want to use generics so the matrices can be any type of number: float, double, int, etc. I have thus set up the class like this:
public class Matrix<num>
Upon initialization, the instantiation of this class creates a matrix based on user supplied data, stored in the instance's .matrix variable. Now, in the code where I want to add up all of the cells, I do something like this:
public num addMatrices(num[][] toAdd){
num result;
if (toAdd.length != this.rows && toAdd[0].length != this.columns){
System.out.println("Matrix mismatch. Try Again.");
return toAdd[0][0];
}
for (int i=0; i<rows; i++)
for (int j=0; j<rows; j++){
result = this.matrix[i][j] + toAdd[i][j];
}
}
I'm running into multiple problems, however. First of all, I can't initialize result to zero, which makes it hard to perform += operations. Secondly, when I try to add the cells of the two matrices, the compiler tells me that the + operator is undefined for the type num.
I thought the whole point of generics was to have a catchall type so I could do things like use floats in one case and ints in another, but if I need to specify the type for operators like +, I'm not sure where the advantage comes in...
You can't perform operations like + and - on Objects (some special cases excluded). Generics are all about Object types, so your use case for them isn't ideal.
That said, you can turn your declaration into something like public class Matrix<num extends Number>, which will let you pass in Integer, Double, BigInteger, etc. then you can then use something like num.longValue() or num.doubleValue() to get the long or double representations of your numbers. You would then need to return a double or long or whatever from your method instead of your generic type, though.
the other option would be to create a custom container class that has methods for add, subtract, etc. Then your class declaration can be public class Matrix<num extends Custom>. You would have to figure out how to account for adding longs to doubles and returning the Custom type.
The problem is that you num can be anything. So, for example, what would it need to do if you created a Matrix<Object>?
You could try to make your number extend from Number, but even then you won't be able to use + because java don't know what to cast this generic to.
You could create a method similar to your Matrix with generic that does that. Something like
public static <NUM extends Number> NUM add(NUM[][] matrixA, NUM[][] matrixB, NumFunction<NUM> function) {
// all equals to your add method, but the result you get with
result = function.apply(this.matrix[i][j], toAdd[i][j]);
}
public interface NumFunction<NUM extends Number> {
NUM apply(NUM operA, NUM operB);
}
You will need to duplicate NumFunction to every type of Number, or create one generic that checks what type of Number is with "instanceof". It's not very pretty :P
Related
I would like to pass different arrays of changing parameter types at different times into a method/function of which randomly returns one element, however am extremely struggling to do so using Java.
I have attempted to do so using the following code:
public int rndInx(Array theArray) {
theArray = theArray[(int)(Math.random() * theArray.length)];
return theArray;
}
However, Eclipse draws attention to errors; length not being resolved and the type of expression must be an array type. I assume one cause of the issue is the returnType, however I'm unsure what type would accept a range of returnTypes. I am aware that the syntax is probably extremely wrong too since I've only recently began to learn Java :(
For example, if I was to pass an array containing integers, then one random integer element would be returned - and if I was to pass an array containing strings etc. than one random element from the array in question would be returned.
Thanks in advance.
Here are the steps to achieve your end goal.
overload the method rndInx for int[] parameter, double[], long[] and so forth for however many primitive types you need to consider.
create a generic method for reference types
here is a hint for the generic method:
public <T> T rndInx(T[] theArray) {
return theArray[....]; // return the element at a random index
}
You can use a generic method:
public <T> T rndInx(T[] array) {
int index = (int)(Math.random() * array.length);
return array[];
}
But this won't work for primitive arrays. If you must accept primitive arrays, you'll have to use reflection and hope the caller has the right type:
public <T> T rndInx(Object array) {
int index = (int)(Math.random() * Array.getLength(array));
return (T)Array.get(array, index);
}
Or return Object and let the caller do the casting.
What you want is to use generics, e.g. like this:
public <T> T selectOneRandomly(T[] array) {
return array[(int)(Math.random() * array.length)];
}
This should work for anything except primitives like int, double etc.
For those you'd either have to provide special methods via overloads (e.g. int selectOneRandomly(int[] array)) or convert the arrays of primitives to arrays of wrapper types (i.e. int[] to Integer[]) before passing the converted arrays to your method.
I'm currently working on generic Sum projection for one of my projects. The code is like,
public class Sum<T,U extends Number> implements IProject<T,U,U>
{
#Override
public U eval(Iterable<T> tList, Function<T,U> property)
{
U total;
for (T t : tList)
{
total += property.apply(t);
}
return total;
}
}
However there is a little glitch here since I need to initialize the total (obviously to 0). But is there anyway to do it in java like in C# I could use default(U).
Java's equivalent to C#'s default(T) is null, which clearly would not work in your case, because you would get a NullPointerException the first time you tried to add something to your total.
In order to initialize your total you would need a factory method in java, but it still would not work, because:
you cannot use += on generics in java.
java.lang.Number is immutable, so you cannot add anything to it.
You have two options.
The massively overengineered approach:
Define a new interface called, say, MyNumber which contains an add method, and write associated non-immutable numeric classes implementing this interface, so your code would then look like this:
#Override
public <T extends MyNumber> T add( T total, Iterable<T> myNumbers )
{
for( T myNumber : myNumbers )
total.add( myNumber );
return total;
}
(You would also need to write a factory so that you can create an instance to hold your total without knowing precisely what type it is.)
The pragmatic approach:
Write cascaded if statements like this:
if( number instanceof Integer )
{
//declare int total
//loop to sum integers
//box the total into a Number
}
else if( number instanceof Long )
{
//declare long total
//loop to sum longs
//box the total into a Number
}
...
Generics only exist for reference types anyway, so this would always be null. There also seems to be an implicit assumption that the + operator is defined for U - are you sure there aren't more constraints on what U can be? Also have you looked at doing Stream.map followed by Stream.reduce? (I assume you are using Java 8 as you have Function)
EDIT I think what you are looking for is the monoid pattern. It doesn't exist in Java but you can define it yourself -
interface Monoid<T>
{
T getZero();
T add(T left, T right);
}
And thus your example would become
public U eval(Iterable<T> tList, Function<T,U> property, Monoid<U> m)
{
U initial = m.getZero();
return StreamSupport.stream(tList.spliterator(), false)
.map(property)
.reduce(initial, (uLeft, uRight) -> m.add(uLeft, uRight));
}
but that would require changing the signature of eval, which might not be possible as I see it's annotated #Override.
This approach is extensible to Lists and Strings with Concatenation, Sets with union and Maps where the value is itself a monoid, "adding" all values of a given key, and functions under composition where the "zero" is the identity function.
I'm a beginner in Java programming, and I'm trying to make a voting machine program, where you can vote for Republicans or Democrats. My question is, how can I edit my method so I would be able to return two strings with two distinct values?
For example, look at my code all the way in the bottom. It's wrong, but I wanted the tester to be able to print out Democrats: (some number) and Republicans: (some number) in one method. How can I do that?
import java.lang.String;
public class VotingMachine1 {
private double Democrats;
private double Republicans;
public VotingMachine1() {
Democrats = 0;
Republicans = 0;
}
public void voteRepublican() {
Republicans = Republicans + 1;
}
public void voteDemocrat() {
Democrats = Democrats + 1;
}
public void clearMachineState() {
Republicans = 0;
Democrats = 0;
}
//this is where I'm having difficulties. I know its wrong
public double getTallies() {
System.out.println("Democrats: ", return Democrats);
System.out.println("Republicans: ", return Republicans);
}
}
No return is necessary there, since you aren't leaving a function. To do what you seem to want to do, just replace that last method with the following:
public void getTallies()
{
System.out.println("Democrats: " + Double.toString(Democrats));
System.out.println("Republicans: " + Double.toString(Republicans));
}
Also, since your votecounts should only ever be integers, there's no reason to declare them as doubles instead of ints.
What you are looking for here is a format string. A format string is used when you know what your output should look like, and only have a few "holes" where unknown data should be filled in. To output your data using format strings, you would use the System.out.format(String, Object...) method:
System.out.format("Democrats: %f\n", Democrats);
System.out.format("Republicans: %f\n", Republicans);
In this case, the %f indicates that a floating-point number (since your variables are declared as double) will be printed instead of the %f. However, you may wish to consider declaring them as int (or long) instead, in which case you would use %d instead of %f in the format strings.
Finally, you ought to change your getTallies() method to return void instead of double, as you are printing the values, not returning them.
Your code and your description are so contradictory, it is not clear that you even know what you are trying to do. I believe that this is the real root of your problems.
Here goes:
public double getTallies()
{
System.out.println("Democrats: ", return Democrats);
System.out.println("Republicans: ", return Republicans);
}
First, your question says that you want to "return two strings with two values" ... but you have declared the method as returning one double.
Next, your code is printing values ... not returning them.
You've also made some major mistakes at the syntactic level, largely (I believe) because you are trying to do contradictory things:
return Republicans is not a valid Java expression, so you can't use it as a argument to the println method.
The println method can't be called with two arguments, as your code is trying to do. There is a zero argument version and a number of one argument overloads ... but no overloads with two or more arguments.
Basically, you need to start by making up your mind about what this method is supposed to do. Is it supposed to:
return the tallies (as two doubles)?
return a string representing the two tallies?
return nothing ... and output the two tallies to standard output?
do something else?
Once you've made up your mind:
code the method to do what you've decided it should do, and
chose a method name that correctly reflects what it is supposed to do. Hint: a method that starts with get is conventionally a "getter" that returns the attribute or attributes themselves ... not a String rendering.
double is a bad choice of type for a vote count too:
You cannot have a fractional vote.
You want to represent vote counts precisely and floating point types (like double) are not precise. (Or at least, not in the sense that you require.)
When you attempt to format or output a double, the resulting character string is likely to include a pesky decimal point ... or worse.
You should use int or long instead of double.
Finally, this is a serious Java style violation, and should get you a significant penalty if your marker is paying attention.
private double Democrats;
private double Republicans;
Variable names in Java should start with a LOWER CASE letter.
A few more random comments:
import java.lang.String; is superfluous as all classes in package java.lang are automatically imported in every Java source file.
Votes can not be fractional. People can't vote 0.75 candidate A, and 0.25 candidate B. If you use integer datatypes (int or long), you will be reflecting this fact better. Also, you will be saving yourself a lot of headache when you start obtaining results like 379857.999999. This is because floating point types have a better range, but worse precision (especially noticeable when working with pure integers).
According to Java usual naming conventions, variable names should start with a lowecase letter.
A better name for function getTallies is printTallies.
For output purposes, it's much better to use string formatting than concatenation. Some advantages are: multiple formats supported, ease of use, and internationalization.
Putting all together:
private int democratVotes;
private int republicanVotes;
public void printTallies() {
System.out.format("Democrats: %,d%n",democratVotes);
System.out.format("Republicans: %,d%n",republicanVotes);
}
In this particular case, votes will be printed with thousand separation (ex: 3,345,623 instead of 3345623). Check Java's Formatting Numeric Print Output tutorial.
Thinking better about it, there are some alternatives where getTallies would effectively be returning some form of value:
1) Make it to return a String with both tallies. It would be hard and inefficient to separate the tallies later, though.
public String getTallies() {
return "Democrats: %,d votes. Republicans: %,d votes.%n".format(democratVotes,republicanVotes);
}
2) Make it to return an array.
public int[] getTallies() {
return new int[2]{ democratVotes, republicanVotes };
}
public int[] getTallies1() { // Same as getTallies, but written step by step.
int[] result= new int[2] ;
result[0]= democratVotes ;
result[1]= republicanVotes ;
return result ;
}
3) Make it to return a class.
public VotingMachineResults getTallies() {
return VotingMachineResults(democratVotes,republicanVotes) ;
}
public static class VotingMachineResults {
private int democratVotes;
private int republicanVotes;
public VotingMachineResults(democratVotes,republicanVotes) {
this.democratVotes= democratVotes ; // `this` required to disambiguate field democratVotes from parameter democratVotes.
this.republicanVotes= republicanVotes ;
}
public int getDemocratVotes() {
return democratVotes ;
}
public int getRepublicanVotes() {
return republicanVotes ;
}
}
As you can see, this class is very similar to VotingMachine1, but it does not accept internal state changes. It is a "value" class.
In Java, you concatenate Strings with the + operator. Proper syntax for what you were trying to do looks like this:
System.out.println("Democrats: " + Democrats);
System.out.println("Republicans: " + Republicans);
A return statement is only used when you want to return some object or value to a method that called your current method. It is not appropriate in this place since you're only passing a value to another method (println()).
ALSO, you need to fix your getTallies() method. Make it return void instead of double since you aren't returning anything.
Here's something completely different: why not override toString()?
Presumably, any instance of VotingMachine1 will apply for all votes that you care about for that instance. That is to say, you don't create a new instance of a VotingMachine1 every time someone casts a vote.
So, what you can do is override the toString() method. We'll also use String.format() to handle the numerical values.
#Override
public String toString() {
// assumes that Democrats and Republicans are declared as int
// since it's pointless to indicate percentages of a vote
return String.format("Democrats: %d\nRepublicans: %d", Democrats, Republicans);
}
Now, whenever you vote, you can use the toString() method to get the information (which is called whenever one does System.out.println(object).
VotingMachine1 voter = new VotingMachine1();
voter.voteDemocrat();
voter.voteRepublican();
System.out.println(voter);
/* This prints:
Democrats: 1
Republicans: 1
*/
A less specific answer to your question would be to return an Object called (say) Votes
public class Vote {
int democratVotes
int republicanVotes
}
and then make your VotingMachine class simply return an instance of this object (suitably changed to make it immutable).
On my project we have created a generic version of this called a Tuple that returns a pair of values in a single object - it has an overloaded toString method for easy printing.
you can return an array with [0] and [1] as key and devide it on the basis of your need..
like
returnArray[0]="first string";
returnArray[1]="second string";
and use it ur way...
I have a hierarchy, which I'll simplify greatly, of implementations of interface Value. Assume that I have two implementations, NumberValue, and StringValue.
There is an average operation which only makes sense for NumberValue, with the signature
NumberValue average(NumberValue numberValue){
...
}
At some point after creating such variables and using them in various collections, I need to average a collection which I know is only of type NumberValue, there are three possible ways of doing this I think:
Very complicated generic signatures which preserve the type info in compile time (what I'm doing now, and results in hard to maintain code)
Moving the operation to the Value level, and: throwing an unsupportedOperationException for StringValue, and casting for NumberValue.
Casting at the point where I know for sure that I have a NumberValue, using slightly less complicated generics to insure this.
Does anybody have any better ideas, or a recommendation on oop best practices?
As #tafa said, it seems to me an interface would be a good choice. Based on your signature for average, I came up with the below.
AveragableValue
public interface AveragableValue<T> extends Value
{
public T average(T value);
}
NumberValue
public class NumberValue implements AveragableValue<NumberValue>
{
private int _n;
public NumberValue(int n)
{
this._n = n;
}
#Override
public void doSomething()
{
// from Value interface
}
#Override
public NumberValue average(NumberValue value)
{
return new NumberValue((this._n + value._n) / 2);
}
}
Then you can have your collection be of type AveragableValue. Already in your code you must have some kind of if/else clause somewhere to differentiate NumberValue and StringValue to figure out whether to call average or not. So I don't see how this would be more complicated. The hierarchy make sense - AveragableValues are a subtype of Value, and a NumberValue is a type of AveragableValue.
However, that signature for average doesn't look right. It only takes 2 values (this and the argument) and averages them. You then lose the total count of things that have been averaged before. So assuming integers as the values (as I did), something like this:
(new NumberValue(4)).average(new NumberValue(8)).average(new NumberValue(12));
would give you the value 9 instead of 8. Is this what you want? It makes it bad for many calculations done iteratively, as you may be doing with collections.
If you show us some of your code - how these classes are used, the collections holding them, how you are doing averaging right now - I can maybe give a better answer.
I would have create another interface IAveragable which contains the average operation which derives from Value . Then StringValue would implement just Value interface and NumberValue would implement IAveragable.
Then when it is required to use the average operation I would check if the object implements IAveragable.
I'm unable to comment, therefore I'll just post a new answer.
Create an interface for value:
public interface Value<T> {
public T getValue();
}
And one for averagable:
public interface Averagable<T> {
public T average(T value);
}
Then a number value would be something like:
public class NumberValue implements Averagable<Number>, Value<Number>{
public Number average(Number value) {
// do your stuff
}
public Number getValue() {
// do your stuff
}
}
There is no need to let Averagable extend from Value.
Running this code:
public class SomeSet {
public static void main(String[] args) {
Set<Short> s = new HashSet<Short>();
for (short i = 0; i < 100; i++) {
s.add(i);
s.remove(i - 1);
}
System.out.println(s.size());
}
}
Will print the value 100.
Why does it print this value?
s.remove(i - 1);
The line above will attempt to remove Integer objects from the set, because all integer calculations in Java have int (or long) results. Since the set contains Short objects, the remove() method will not have any effect.
This (and similar problems) is the main reason why you should almost never use short (and, more so, Short). Using a Set implementation to contain autoboxed numbers incurs a massive (easily 1000%) overhead, so it's rather pointless to try and save space by using Short rather than Integer.
The problem is that remove(i-1) calls the remove method with an Integer object, since i-1 is of type int (which gets auto-boxed into an Integer).
To make sure that you call remove with a Short object use this:
s.remove((short) (i - 1));
The type of i - 1 is int, so it gets autoboxed to an Integer.
Normally you'd expect a generic collection to prevent you performing operations which have arguments of the wrong type, but the interface to Set<E> is a bit loose.
Because the remove method of Set<E> takes an Object rather than an E, the compiler doesn't warn you that you're removing a different type to what the set contains.
To force it to be a Short, cast the numeric value to (short). (casting to (Short) isn't allowed, and you'd have to cast the numeric value to use Short.valueOf)
Note that the add method is generically typed boolean add(E o) so in your case of Set the add method will take a short, whereas the remove method is not generically typed boolean remove(Object o) so i - 1 autoboxes to a Integer. For any value of i new Short(i).equals(new Integer(i)) will always be false.
Note that if you try s.add(i - 1); you will get a compiler error because i - 1 becomes an instance of Integer and the types Integer and Short do not match.