1

I have a simple class called Employee.

public class Employee<T extends Number> {
    private final String id; 
    private final String name;
    private final T salary; //generic type salary

    public Employee(String id,String name,T salary){
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public T getSalary() {
        return salary;
    }

}

Here using reduction, i am able to add Double type. But i need generic type addition. The values in the salary can be either Double or Integer. So is there any way to use provide any flexibility so that i can add any Sub type of Number.

  public static void main(String[] args) {
        //creates employee list and three employees in it
        List < Employee > employees = new LinkedList < > ();
        employees.add(new Employee("E001", "John", 30000.00));
        employees.add(new Employee("E002", "Mark", 45000.00));
        employees.add(new Employee("E003", "Tony", 55000.00));
        employees.stream().map(Employee::getSalary).reduce(0, (a, b) -> {
        //only able to add double type values, but i need any sub type of number
                return a.doubleValue() + b.doubleValue();
            });
    }



Please help me. 
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
  • 1
    Possible duplicate of [Can I do arithmetic operations on the Number baseclass?](http://stackoverflow.com/questions/3873215/can-i-do-arithmetic-operations-on-the-number-baseclass) – sovas May 15 '17 at 12:37
  • What errors do you get? – BetaRide May 15 '17 at 12:38
  • I am not getting any error. I need to know one way, so that i am able to add either integer or double. employees.stream().map(Employee::getSalary).reduce(0, (a, b) -> { //only able to add double type values, but i need any sub type of number return a.doubleValue() + b.doubleValue(); }); Here, i have bounded the addition of double. I need to know that is there any way so that i can eliminate this bound and use any number type addition. – Subhabrata Mondal May 15 '17 at 12:40
  • 2
    No sane programmer would use `double` values for monetary values. Likewise, the idea of abstracting the actual type of both, storage and calculations, of salaries makes no sense. It causes problems for no benefit. – Holger May 15 '17 at 14:58
  • Generifying over numbers never, ever goes well. Never. Pick one number type for the whole program and stick with it. – Louis Wasserman May 15 '17 at 16:39

2 Answers2

4

I would suggest you to first add the correct generic type arguments in your variable declarations:

List<Employee<Double>> employees = new LinkedList<>(); // you need to add "<>"s here
employees.add(new Employee<>("E001", "John", 30000.00));
employees.add(new Employee<>("E002", "Mark", 45000.00));
employees.add(new Employee<>("E003", "Tony", 55000.00));

Then, this will return a double which is convertible to Number, and Number can be converted to int, float, short etc:

Number num = employees.stream().map(Employee::getSalary).reduce(0.0, (a, b) -> {
        return a + b;
});

Alternatively, just get rid of the generics. Instead of using T, just use Number as the type of salary.

class Employee {
    private final String id;
    private final String name;
    private final Number salary; //generic type salary

    public Employee(String id,String name,Number salary){
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Number getSalary() {
        return salary;
    }

}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • If i take the first approach i.e – Subhabrata Mondal May 15 '17 at 12:58
  • ' List> employees = new LinkedList<>(); employees.add(new Employee("E001", "John", 30000.00)); employees.add(new Employee("E002", "Mark", 45000.00)); employees.add(new Employee("E003", "Tony", 55000.00)); Number num = employees.stream().map(Employee::getSalary).reduce(0.0, (a, b) -> { return a + b; });' It gives me error.. bad operand types for binary operator '+' first type: Number second type: Number – Subhabrata Mondal May 15 '17 at 12:59
  • Sorry, you have specified, Employee, Yes Number class does not have addition operation. But i need to know that can i use if -else statement in the accumulator section in the reduce() method so that i can check the instance type for a and b based upon that i can apply addition to the correct type. like return a.doubleValue() + b.doubleValue(); Please tell me is there any trick or way available in Java or not. – Subhabrata Mondal May 15 '17 at 13:09
  • @SubhabrataMondal No you don't do that. You don't check what specific type of `Number` it is. That is the whole point of using generics. You should just return a `double` and then assign that to a variable of type `Number`. After that, you can convert the `Number` to other types using `intValue()`, `shortValue()` etc. – Sweeper May 15 '17 at 16:31
0

There's no easy out of this... As the compiler can't do addition via + on two Numbers. You could of course use a cast here. The deeper problems might arise when an Employee has salary of type Double, but another of type Long for example, in which case casts are going to get pretty nasty.

One approach if you are ok with returning a BigDecimal is this:

  BigDecimal r = employees.stream().map(Employee::getSalary)
            .map(n -> new BigDecimal(n.toString()))
            .reduce(BigDecimal.ZERO, (left, right) -> {
                return new BigDecimal(left.toString()).add(new BigDecimal(right.toString()));
            });
Eugene
  • 117,005
  • 15
  • 201
  • 306