public class Generics {
public static <T> T increaseBalance (T amount){
//say I want to increase the amount here, put it into finalBalance and return
return finalBalance;
}
public static void main(String[] args){
System.out.println(increaseBalance (new Integer(10)));
System.out.println(increaseBalance (new Double(20)));
}
}
Hi. I am just into Generics and auto/unboxing. In this simple code segment, I am trying to send two different objects to increaseBalance(T amount) method and would like to increase the amount by 10 and return the final balance. How can this be achieved? It would make my understanding of generics and auto/unboxing clearer. Thanks a lot.
Unfortunately, there's no easy way to apply the + operator to a Generic type T.
You have two options:
Overloading
or
Checking the type and casting to a specific boxed type
If you pick to overloading, you can implement two methods, both for each of the possible parameter types.
public static Integer increaseBalance (Integer amount){
return amount + 10;
}
public static Double increaseBalance (Double amount){
return amount + 10;
}
If you want to stick to the generic method, you will have to check the parameter type and then do a cast.
public static <T extends Number> Number increaseBalance (T amount){
Number result = null;
if (amount instanceof Integer) {
result = new Integer((Integer) amount + 10);
} else if (amount instanceof Double) {
result = new Double((Double) amount + 10);
} else {
//do nothing
}
return result;
}
Related
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.
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));
}
}
An instructor recently set the task of coding a small calculator class for integers and doubles. As worded the assignment is covered by the following:
public final class Calculator {
public int add(int augend, int addend) { return augend + addend; }
public double add(double augend, double addend) { return augend + addend; }
public int subtract(int minuend, int subtrahend) { return minuend - subtrahend; }
public double subtract(double minuend, double subtrahend) { return minuend - subtrahend; }
public int divide(int dividend, int divisor) { return dividend / divisor; }
public double divide(double dividend, double divisor) { return dividend / divisor; }
public int multiply(int multiplicand, int multiplier) { return multiplicand * multiplier; }
public double multiply(double multiplicand, double multiplier) { return multiplicand * multiplier; }
}
I am wondering though, given that the methods are functionally the same if the
duplication of the functionality could be removed somehow by the use of generics?
I have tried a couple of routes to make this happen, the latest is to make the entire class generic as follows, but keep getting stuck where it comes to actually applying the mathematical operations to the variables
public class Calculator<T extends Number> {
public T add(T augend, T addend) {
// addition is the same for any number type
return augend + addend; // "operator '+' cannot be applied to 'T','T'"
}
// etc...
}
The error message, or a variant thereof, comes into play with whichever method I try... Is there a better way to do this? (with or without generics)
I don't think you can apply operators on Type T. Since during compilation this will get replaced with the object in case of unbounded Type and with the first bound in case of bounded type. Refer https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html. In the below code, it would get replaced with Number but Number doesn't work with operators.
You can create an generic interface like this :
interface Calc<T extends Number>{
T add(T a, T b);
}
Now create Concrete Classes for Integer and Doubles
class IntegerCalc implements Calc<Integer>{
#Override
public Integer add(Integer a, Integer b) {
return a+b;
}
}
class DoubleCalc implements Calc<Double>{
#Override
public Double add(Double a, Double b) {
return a+b;
}
}
You did it fine! Pretty simple and reliable code. Good Job.
P.S. Think about that generics work with Object, and Integer and int is not absolutely the same thing. If you can work with a simple type, you should do it and avoid wrappers.
As a new programmer, I don't know how methods are really works. But when I used Object, can they give me any int, float or double value? And can it be used as integer, float, double!? Please help me. Thanks.
import java.util.Scanner;
public class ProjectBookShop {
static Scanner scan= new Scanner(System.in);
static String[] books = {"Java", "C", "CSS"};
static final double studentDiscount = 0.3;
static final double teacherDiscount = 0.4;
static final double alienDiscount = 0.0;
static final int balance = 150;
public static void main(String[] args) {
prln("<---- WELCOME TO OUR BOOK SHOP --->");
prln("Today we are offering you" +balance + "Taka");
prln("Which books do you want:\n Ans:");
String usersChoice= scan.nextLine();
if(books[0].toLowerCase().equals(usersChoice.toLowerCase()))
{
prln("You opted for Java.");
calculatePrice(books[0]);
//Problem starts from this line.
if(balance => showPrice(calculatePrice(books[0])))
{
prln("You are eligible for buying this book!");
}
}else if(books[1].toLowerCase().equals(usersChoice.toLowerCase()))
{
prln("You opted for C.");
calculatePrice(books[1]);
}else if(books[2].toLowerCase().equals(usersChoice.toLowerCase()))
{
prln("You opted for Css.");
calculatePrice(books[2]);
}
else
{
prln("We dont have this book.");
}
}
// These are called methods!
static void calculatePrice(String bookName)
{
double price = 200;
prln("Are you a student, teacher or alien:\n Ans:");
String answer = scan.nextLine();
if(answer.toLowerCase().equals("student"))
{
price = price - (price*studentDiscount);
showPrice(price);
}else if(answer.toLowerCase().equals("teacher"))
{
price = price - (price * teacherDiscount);
showPrice(price);
}else if(answer.toLowerCase().equals("alien"))
{
price = price - (price * alienDiscount);
showPrice(price);
}else
{
prln("We dont offer any books for you!!");
showPrice(price);
}
}
static void showPrice(Object price)
{
prln("Your total price will be: "+ price);
prln("<---- Thanks for shoping with us. --->");
}
static void prln(Object anyObject)
{
System.out.println(anyObject);
}
static void pr(Object anyObject)
{
System.out.print(anyObject);
}
}
Yes, primitive types like int, double or boolean can be assigned to Objects. It is done using wrapper types:
byte - Byte
short - Short
int - Integer
long - Long
float - Float
double - Double
char - Character
boolean - Boolean
void - Void
Note Void is special. As void has no value, the only value assignable to Void is null.
Objects cannot be used as primitive types unless you cast them to right type:
Object ob = myObjectStream.readObject();
Integer intg = (Integer) ob;
Warning: attempting to cast a float wrapped as Float and assigned as Object to Integer will result in ClassCastException being thrown. To prevent it, you may use instanceof:
Object ob = myObjectStream.readObject();
if(ob instanceof Integer) {
int x = (Integer) ob;
// Do something
} else if(ob instanceof Float) {
float f = (Float) ob;
// Do something else
} else {
System.err.println("I don't support provided object class!!!");
}
Did you notice an assignment to float from Float? This works in both sides:
float x = 1.0f;
Float y = x;
float z = y; // == 1.0f
That is automatic boxing/unboxing. If you don't want to use it, you may still do it by hand:
float x = 1.0f;
Float y = Float.valueOf(x);
float z = y.floatValue(); // == 1.0f
This works for all wrapper types except Void.
Also, instead of:
String s1, s2;
if(s1.toLowerCase().equals(s2.toLowerCase()) {
// ...
}
Use:
String s1, s2;
if(s1.equalsIgnoreCase(s2) {
// ...
}
This deals properly with some corner-case Unicode characters.
Operator => does not exist. Did you mean >=?
If method showPrice is always given doubles, wrapped into Doubles, there's no sense to make it wrap them; wrapping takes time. If it is given only Doubles, rewrite it to following:
static void showPrice(double price)
{
prln("Your total price will be: "+ price);
prln("<---- Thanks for shoping with us. --->");
}
This works the same and is faster.
pr is never used! Remove it and save code. Also, when class is loaded, all its methods are loaded. So, if you remove it, you can also make your program boot faster.
As some comments suggest, you try comparing void. Rewrite showPrice once again:
static double showPrice(double price)
{
prln("Your total price will be: "+ price);
prln("<---- Thanks for shoping with us. --->");
return price;
}
This makes the comparison work.
You do not want to use Object for your method arguments. Object is the base Object that every other object in Java is derived from, but in your case, when a parameter is passed (such as a double) to a method that has an Object argument, the receiving method no longer "sees" it as a double, so it can not interpret it as a number.
You should change your prln and pr methods and instead use:
static void showPrice(double price)
{
prln("Your total price will be: "+ price);
prln("<---- Thanks for shoping with us. --->");
}
static void prln(String str)
{
System.out.println(str);
}
static void pr(String str)
{
System.out.print(str);
}
I have two different types of Sets that need to be iterated and one of the values of the objects of the set need to be summed. How can I do this with Generics, i.e without writing two summing methods for each type of Set?
private Double calculateFooScoreSum(final Set<Foo> fooScoreSet)
{
Double sum = 0.0;
for (final Foo score : fooScoreSet)
{
sum += score.getScore();
}
return sum;
}
private Double calculateBarScoreSum(final Set<Bar> barScoreSet)
{
Double sum = 0.0;
for (final Bar score : barScoreSet)
{
sum += score.getScore();
}
return sum;
}
How can I write the above two methods using Generics as a single method. Something Like:
private static Double calculateScoreSum(Set<?> scoreSet)
{
Double sum = 0.0;
for(Object scoreObj : scoreSet){
//Some casting magic
sum+=score.getScore();
}
return sum;
}
If it helps, getScore() method exists in both classes Foo and Bar.
Any ideas and suggestions are much appreciated.
Thanx
Define a common interface, say Scorable:
public interface Scorable {
int getScore();
}
And implement it with Foo and Bar:
public class Foo implements Scorable {
public int getScore () { return 1; }
}
public class Bar implements Scorable {
public int getScore () { return 2; }
}
And then, define a method that can accept any kind of Scorable, using wildcards:
private static Double calculateScoreSum(Set<? extends Scorable> scoreSet) {
Double sum = 0.0;
for (Scorable score : scoreSet){
sum += score.getScore();
}
return sum;
}
Which can receive either Set<Foo> or Set<Bar> since they both implement Scorable.