Java generics array operation - java

I have a Vector generic class that contain an array of that contains elements of type T, and i want to have vector addition(for int, double, float, ... of course not boolean,... ) in my class, but i can't do "array_vector[i]", how use operator without know the type ?
public class vector<T> {
private T[] array_vector;
public vector(){
this.array_vector = null;
}
public vector(T[] array_p){
this.array_current = array_p;
}
public void vectorAddition(T[] array_other){
if(this.array_vector.length == array_other.length){
for(int i=0; i<this.array_vector.length ; i++){
this.array_vector[i] += array_other[i];
}
}
}
}

You can't do this directly; you need an instance of BinaryOperator<T>:
this.array_vector[i] = binaryOperator.apply(this.array_vector[i], array_other[i]);
For example:
BinaryOperator<Double> = (a, b) -> a + b;
BinaryOperator<Integer> = (a, b) -> a + b;
Pass one of these into the constructor of vector, e.g.
public vector(BinaryOperator<T> binaryOperator, T[] array_p){
// assign to a field.
}

First of all, if you always use numbers, maybe it's for the best to declare T extends Number to ensure strong typing checks no matter the solution applied:
public class vector<T extends Number> {
About solutions, I think that the more similar solution to the user's case is to use instanceof checks inside the vectorAddition method:
if (array_vector instanceof Integer[]) {
for (int i = 0; i < array_vector.length; ++i) {
array_vector[i] =
(T)(Integer)(array_vector[i].intValue() +
array_other[i].intValue());
}
} else if (array_vector instanceof Double[]) {
for (int i = 0; i < this.array.length; ++i) {
array_vector[i] =
(T)(Double)(array_vector[i].doubleValue() +
array_other[i].doubleValue());
}
//} else if (array_vector instanceof ...[]) {
// ... declare other supported types
} else {
// throw exception because not supported
}
However maybe is better to define some binary operator classes for common Number children and autoset it in the constructor, based on the array_vector instance with something like:
if (array_vector instanceof Integer[]) {
// ...
} else if (array_vector instanceof Double[]) {
// ...
} else if (array_vector instanceof ...[]) {
// ...
} else {
// throw exception because not supported
}
And maybe define a custom binary operator constructor if desired/needed.

Related

Java: How to add two generics of java.lang.Number in a function and design pattern of Matrix in Java? [duplicate]

I would like to generically add numbers in java. I'm running into difficulty because the Numbers class doesn't really support what I want to do. What I've tried so far is this:
public class Summer<E extends Number> {
public E sumValue(List<E> objectsToSum) {
E total = (E) new Object();
for (E number : objectsToSum){
total += number;
}
return null;
}
Obviously this will not work. How can I go about correcting this code so I could be given a list of <int> or <long> or whatever and return the sum?
In order to calculate a sum generically, you need to provide two actions:
A way to sum zero items
A way to sum two items
In Java, you do it through an interface. Here is a complete example:
import java.util.*;
interface adder<T extends Number> {
T zero(); // Adding zero items
T add(T lhs, T rhs); // Adding two items
}
class CalcSum<T extends Number> {
// This is your method; it takes an adder now
public T sumValue(List<T> list, adder<T> adder) {
T total = adder.zero();
for (T n : list){
total = adder.add(total, n);
}
return total;
}
}
public class sum {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(4);
list.add(8);
CalcSum<Integer> calc = new CalcSum<Integer>();
// This is how you supply an implementation for integers
// through an anonymous implementation of an interface:
Integer total = calc.sumValue(list, new adder<Integer>() {
public Integer add(Integer a, Integer b) {
return a+b;
}
public Integer zero() {
return 0;
}
});
System.out.println(total);
}
}
As Number class does not expose interface for performing calculations, the only way to solve this problem is to create classes which encapsulates required operations for each supported numeric type. Than in your class you will need to use specific type.
Number has intValue(), floatValue(), doubleValue(), longValue, and shortValue(). Choose one and use it. For example,
double total;
total += number.doubleValue();
return total;
Also, java generics are in no way equivalent to c++ templates. You can not allocate new instances of a java generic type. This can never work:
E hoot = (E) new Object();
Finally, long, short, int, double, and float are not class types; they are primitive types. As such they are not available for use with Java generics.
below method get numbers such as int, float, etc and calculate sum of them.
#SafeVarargs
private static <T extends Number> double sum(T... args) {
double sum = 0d;
for (T t : args) {
sum += t.doubleValue();
}
return sum;
}
Number doesn't support any operations so you need to cast the values to the types required. e.g. If Number is a BigDecimal, there is no += operator.
You should check runtime type (e.g. using instanceof) and cast to the known type and do appropriate addition operation. Not sure what will be type of result, taking in account that the list could contain a lot of different number types.
since the introduction of Java 8 streams and lambda you can have a shorter solution
public interface Adder {
static <E extends Number> E sumValues(Collection<E> objectsToSum, BinaryOperator<E> sumOp) {
return objectsToSum.stream().reduce(sumOp).orElse(null);
}
}
and use it as follows
int sum = Adder.sumValues(List.of(4, 5, 6, 7), Integer::sum);
Note, that Stream::reduce with just accumulator returns Optional that's why I used orElse(null), but I would recommend to send also zero value as parameter to Adder::sumValue
not elegant, but works
public class GenericSum {
public static <T extends Number> Number sum(T x, T y) throws Exception{
// Field
Field primitiveField = x.getClass().getField("TYPE");
// int|float... object
var primitiveType = primitiveField.get(null);
// cast to class
var adder = x.getClass().getMethod("sum", (Class)primitiveType,(Class)primitiveType);
var result = adder.invoke(null,x, y);
return (Number) result;
}
public static void main(String[] args) throws Exception {
var a1 = 3;
var a2 = 5;
var res = sum(a1, a2);
System.out.println(res);
var b1 = 2.0f;
var b2 = 3.0f;
var res2 = sum(b1,b2);
System.out.println(res2);
}
}
I was looking for any implementation of a generic adder accumulator when I came across this question.
I feel this is a lot messy and ugly for most use cases but if you need a very generic one here it is.
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.function.BinaryOperator;
public class Adder implements BinaryOperator<Object> {
#Override
public Object apply(Object partialSum, Object element) {
// if both are instances of Number, then add them
// otherwise we parse the element as string
// and add it to the partial sum
if(partialSum instanceof Number) {
if(element instanceof Number) {
if(partialSum instanceof Integer)
return (Integer) partialSum + ((Number) element).intValue();
if(partialSum instanceof Long)
return (Long) partialSum + ((Number) element).longValue();
if(partialSum instanceof BigInteger)
return ((BigInteger) partialSum).add(BigInteger.valueOf(((Number) element).longValue()));
if(partialSum instanceof Float)
return (Float) partialSum + ((Number) element).floatValue();
if(partialSum instanceof Double)
return (Double) partialSum + ((Number) element).doubleValue();
if(partialSum instanceof BigDecimal)
return ((BigDecimal) partialSum).add(BigDecimal.valueOf(((Number) element).doubleValue()));
else
throw new NumberFormatException("Unknown number type for partialSum: " + partialSum.getClass());
}
else {
if(partialSum instanceof Integer)
return (Integer) partialSum + Integer.parseInt(element.toString());
if(partialSum instanceof Long)
return (Long) partialSum + Long.parseLong(element.toString());
if(partialSum instanceof BigInteger)
return ((BigInteger) partialSum).add(new BigInteger(element.toString()));
if(partialSum instanceof Float)
return (Float) partialSum + Float.parseFloat(element.toString());
if(partialSum instanceof Double)
return (Double) partialSum + Double.parseDouble(element.toString());
if(partialSum instanceof BigDecimal)
return ((BigDecimal) partialSum).add(new BigDecimal(element.toString()));
else
throw new NumberFormatException("Unknown number type for partialSum: " + partialSum.getClass());
}
}
throw new NumberFormatException("partialSum " + partialSum + " must be of type java.lang.Number but found " + partialSum.getClass());
}
}
Honestly this would've been a lot simpler if generic Number types supported the + operator like how Strings does.

Java Comparing three generic elements

I want to compare a collection (ArrayList) of elements if they are the same type. In the beginning I do not know what type the elements are (generic types), so I decided to use Object type. But I still cannot compare them. The problem is in the function triplesort().The warning is:
Operator '>' cannot be applied to 'java.lang.Object', 'java.lang.Object'. If you have any possible solutions to that problem and you let me know, I would be grateful. <3
Triple.java
import java.util.ArrayList;
public class Triple<T, S, U> {
private T t;
private S s;
private U u;
private ArrayList<Object> array = new ArrayList<Object>();
Triple(T t, S s, U u) {
setT(t);
setS(s);
setU(u);
array.add(this.t);
array.add(this.s);
array.add(this.u);
}
public void setT(T t) {
this.t = t;
}
public void setS(S s) {
this.s = s;
}
public void setU(U u) {
this.u = u;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
public U getThird() {
return u;
}
public String toString() {
return t + "\n" + s + "\n" + u + "\n";
}
public boolean isHomogeneous() {
return t.getClass() == s.getClass() && t.getClass() == u.getClass();
}
public void tripleSort() {
try {
for (int i = 1; i < array.size(); ++i) {
Object key = array.get(i);
int j = i - 1;
while (j > -1 && array.get(i) > key) {
array.set(j + 1, array.get(j));
j--;
}
array.set(j + 1, key);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
There are two main issues with code you've provided:
Relational operators <, <=, >, >= can be used only to compare numeric primitive types. Obviously, you can use it with objects.
To compare reference types you can use Comparator or these objects can implement Comparable interface (i.e. they basically are aware how to compare themselves). But it doesn't make since to compare BigDecimal and Boolean, or String and HashMap, how would you approach that? For that reason, these interfaces are generic and Comparator<T> can't be used with objects of type U.
That said, your Triple<T, S, U> would not be able to do a lot with these objects belonging to different type (definitely you can't sort them).
Hence, if you need a data-carrier holding references of three distinct types, that fine. It's still can be useful, but don't expect from it much.
A Java 16 record fits in this role perfectly well:
public record Triple<T, S, U>(T first, S second, U third) {}
But if you need to able to operate with these values comparing them with one another then consider changing the Triple to hold only elements of type T.
Here's an example of how it might be implemented:
public static class Triple<T> {
private List<T> list = new ArrayList<>(3);
private Comparator<T> comp;
private Triple(T first, T second, T third, Comparator<T> comp) { // no way and no need to invoke this constructor outside the class
this.comp = comp;
Collections.addAll(list, first, second, third);
}
public static <T> Triple<T> getInstance(T first, T second, T third, Comparator<T> comp) {
Triple<T> triple = new Triple<>(first, second, third, comp);
triple.init();
return triple;
}
public void init() {
list.sort(comp);
}
public T getFirst() {
return list.get(0);
}
public T getSecond() {
return list.get(1);
}
public T getThird() {
return list.get(2);
}
public boolean isHomogeneous() {
return comp.compare(getFirst(), getSecond()) == 0
&& comp.compare(getFirst(), getThird()) == 0
&& comp.compare(getSecond(), getThird()) == 0;
}
public String toString() {
return list.stream().map(T::toString).collect(Collectors.joining("\n"));
}
}
Usage example:
Let's consider a Triple storing integer value in Descending order.
public static void main(String[] args) {
Triple<Integer> intTriple = Triple.getInstance(5, 3, 12, Comparator.reverseOrder());
System.out.println(intTriple);
}
Output:
12
5
3

Java method overloading -- combining methods into a single one in some cases? [duplicate]

This question already has answers here:
Code duplication caused by primitive types: How to avoid insanity?
(8 answers)
Closed 3 years ago.
While I understand the importance of method overloading, but I'm curious if its possible to write a single add function for the following code:
public class Add {
public int add(int i, int j) {
return i + j;
}
public double add(double i, double j) {
return i + j;
}
}
The other answer will not work, but if we modify it a little bit, it can work:
public Number add(Number i, Number j) {
if(i instanceof Integer && j instanceof Integer) {
return i.intValue() + j.intValue();
} else if(i instanceof Double && j instanceof Double) {
return i.doubleValue() + j.doubleValue();
} //you can check for more number subclasses
return null; //or throw and exception
}
But this is so much uglier then overloading.
Instead of overloading, you can have a generic approach.
public static class Utils {
public static <T extends Number> Number multiply(T x, T y) {
if (x instanceof Integer) {
return ((Integer) x).intValue() + ((Integer) y).intValue();
} else if (x instanceof Double) {
return ((Double) x).doubleValue() + ((Double) y).doubleValue();
}
return 0;
}
}
and use it like this
Utils.<Double>multiply(1.2, 2.4); // allowed
Utils.<Integer>multiply(1.2, 2.4); // not allowed
Utils.<Integer>multiply(1, 2); // allowed
Of course it is possible. First of all, the double function can accept int values, so you can use that for both if you want. However, if you still want to achieve your goal, the best way is to use generics. Another way is to make your method accept a parent of both classes for example Object and then cast appropriately as shown below:
public class Add {
enum ParamType {
INT,
DOUBLE
}
public static Object add(Object i, Object j, ParamType paramType) {
if (paramType.equals(ParamType.INT)) {
return (int) i + (int) j;
} else {
return (double) i + (double) j;
}
}
public static void main(String[] args) {
System.out.println(add(3.4, 5.2, ParamType.DOUBLE));
System.out.println(add(3, 5, ParamType.INT));
}
}

Java Generics: Comparing an Integer to a Double

Can anyone help me compare an Integer to a Double using generics?
This is what I have:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Number i = new Integer(5);
Number j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
The error message I get is:
Bound mismatch: The generic method compare(T, T) of type GenericsTest is not applicable for the arguments (Number, Number). The inferred type Number is not a valid substitute for the bounded parameter >
The idea of this solution is to widen to BigDecimal and then compare the two numbers (now is cleaner but somehow formatting doesn't work). Note you may reuse this static comparator without having to cast to double anywhere else. In the implementation you do need conversion to double not to lose information, basically you widen to the most general representation.
private static final Comparator<Number> NUMBER_COMPARATOR = new Comparator<Number>() {
private BigDecimal createBigDecimal(Number value) {
BigDecimal result = null;
if (value instanceof Short) {
result = BigDecimal.valueOf(value.shortValue());
} else
if (value instanceof Long) {
result = BigDecimal.valueOf(value.longValue());
} else
if (value instanceof Float) {
result = BigDecimal.valueOf(value.floatValue());
} else
if (value instanceof Double) {
result = BigDecimal.valueOf(value.doubleValue());
} else
if (value instanceof Integer) {
result = BigDecimal.valueOf(value.intValue());
} else {
throw new IllegalArgumentException("unsupported Number subtype: " + value.getClass().getName());
}
assert(result != null);
return result;
}
public int compare(Number o1, Number o2) {
return createBigDecimal(o1).compareTo(createBigDecimal(o2));
};
};
public static void main(String[] args) {
Number i = Integer.valueOf(5);
Number j = Double.valueOf(7);
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(-7);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Double.MAX_VALUE;
// -1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
i = Long.MAX_VALUE;
j = Long.valueOf(Long.MAX_VALUE - 1);
// +1
System.out.println(NUMBER_COMPARATOR.compare(i, j));
// sorting Long values
Long[] values = new Long[] {Long.valueOf(10), Long.valueOf(-1), Long.valueOf(4)};
Arrays.sort(values, NUMBER_COMPARATOR);
// [-1, 4, 10]
System.out.println(Arrays.toString(values));
}
As aready said in the comments, Number does not implement Comparable.
But Double and Integer do.
One way to make this work is like this:
public static <T extends Comparable<? super T>> int compare(T arg1, T arg2)
{
return arg1.compareTo(arg2);
}
public static void main(String[] args)
{
Double i = new Integer(5).doubleValue();
Double j = new Double(7);
System.out.println(GenericsTest.compare(i, j));
}
Number doesn't implement Comparable.
Declare both variables as Integer.
private boolean compareObject(Object expected, Object actual) {
if (expected instanceof Number && actual instanceof Number) {
double e = ((Number) expected).doubleValue();
double a = ((Number) actual).doubleValue();
return e == a;
} else {
return com.google.common.base.Objects.equal(expected, actual);
}
}
Create a class that implements Comparable which takes a Number in the constructor.
e.g.
public class GenericNumber implements Comparable<GenericNumber> {
private Number num;
public GenericNumber(Number num) {
this.num = num;
}
// write compare function that compares num member of two
// GenericNumber instances
}
Then simply do this:
GenericNumber i = new GenericNumber(new Integer(5));
GenericNumber j = new GenericNumber(new Double(7));
System.out.println(GenericsTest.compare(i,j));

How to check that java.lang.reflect.Method return type is Collection?

I have method to get list of bean properities like below. How to check that method return type is collection (like List, Set...). isInstance(Collection.class) doesn't work.
public static List<String> getBeanProperties(String className, boolean withLists) {
ArrayList<String> a = new ArrayList();
try {
Class c = Class.forName(className);
Method methods[] = c.getMethods();
for (int i = 0; i < methods.length; i++) {
String m = methods[i].getName();
if(m.startsWith("get") && methods[i].getParameterTypes().length == 0) {
if((methods[i].getReturnType().isInstance(Collection.class)) && !withLists) {
// skip lists
} else {
String f = m.substring(3);
char ch = f.charAt(0);
char lower = Character.toLowerCase(ch);
f = lower + f.substring(1);
a.add(f);
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return a;
}
use Collection.class.isAssignableFrom(returnType). Reference
Method#getReturnType returns a single Class object, the Class object that corresponds to the method declaration. If the method is declared to return a Collection, you'll see a collection. If it is declared to return a subclass of Collection (List', ..), you'll need to check, ifCollection` is assignable from the actual return type:
Class<?> realClass = methods[i].getReturnType(); // this is a real class / implementation
if (Collection.isAssignableFrom(realClass)) {
// skip collections (sic!)
}

Categories