Carranque
Carranque

Reputation: 33

Type cast inside lambda expression in Java?

I'm using Spring Boot under Java 8 and I'm trying to perform a type cast inside a lambda expression, but can't get it to work after a lot of research and try/error.

Suppose I have a list like this:

List<Foo> list;

that is filled in a step of a batch process, and because of datasource restrictions, the class Foo needs to be declared like this (with all its members as String):

class Foo {

    private String id;
    private String quantity;

    public String getId() {
      return id;
    }

    public void setId(String id) {
      this.id = id;
    }

    public String getQuantity {
      return quantity;
    }

    public void setQuantity(String quantity) {
      this.quantity = quantity;
    }
}

Once the list is loaded, I need to do some grouping and summing based on id, given that the quantity String represents a decimal number.

The following code gives me an error because summingDouble is expecting a Double, not a String:

Map<String, Double> grouping = list.stream().collect(Collectors.groupingBy(Foo::getId, Collectors.summingDouble(Foo::getQuantity)));

I managed it to fix the error by adding an extra function to Foo class, like this:

public Double getQuantityAsDouble() {
    return StringUtils.isEmpty(quantity) ? new Double(0) : Double.valueOf(quantity);
}

and doing the call this way:

Map<String, Double> grouping = list.stream().collect(Collectors.groupingBy(Foo::getId, Collectors.summingDouble(Foo::getQuantityAsDouble)));

but it seems a poor solution to me.

Is there any way to direct cast Foo::getQuantity from String to Double inside Collectors.summingDouble() without the need to add bloat functions to the original bean?

Thanks!

Upvotes: 3

Views: 2333

Answers (1)

Taylor
Taylor

Reputation: 4087

Java doesn't do implicit conversion from String to Double, which is what your code is implying.

You need an explicit conversion, which can be accomplished with with a conversion in the stream:

Map<String, Double> grouping = list.stream().collect(Collectors.groupingBy(Foo::getId,
            Collectors.summingDouble(foo -> Double.parseDouble(foo.getQuantity()))));

(or use Double.valueOf if those semantics are more appropriate)

EDITED: clarity

EDITED MORE: to add explanation based on comment.

The double colon syntax (e.g. Foo::getQuantity) creates a method reference. Double.valueOf only knows how to deal with a string. In this case, java needs some "imperative help" to connect the dots, hence the imperative lambda, rather than the function reference.

Upvotes: 3

Related Questions