1

I have an ArrayList called "Catalog" of Articles (generic Type).

An Article has following Methods:

public int getUnitsInStore()
public long getUnitPrice()

To get the total value of all Articles within the catalog i try to use the Reduce Method of the Java Stream Api.

i tried following:

long value = 0;
    
value = catalog.stream().reduce((a,b) -> a.getUnitPrice()*b.getUnitsInStore());

But this is giving me the error:

Type mismatch: cannot convert from Optional<Article> to long

What im doing wrong?

3
  • 2
    read the doc for reduce: it will tell you what types a and b are, and what they represent exactly. Commented Apr 21, 2021 at 19:43
  • 4
    Your code makes no sense at all. Why would you multiply the price of one article with the unit count of an entirely different article? Sounds like what you need is long total = catalog.stream().mapToLong(a -> a.getUnitPrice() * a.getUnitsInStore()).sum() Commented Apr 21, 2021 at 19:52
  • @Andreas: Yeah, now i know. Thanks for comment. This helps a lot Commented Apr 21, 2021 at 19:57

3 Answers 3

2

The a and b in your accumulator lambda are, respectively, the partial result and the next element in the stream. Since you are reducing over a list of Articles, the partial result is an Article and you cannot add a Long to an Article.

So in your case, you probably want to do something like this.

value = catalog.stream()
            .map(a -> a.getUnitPrice() * a.getUnitsInStore())
            .reduce(0L, Long::sum);
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. Know i understand
.mapToLong(...).sum() is probably more efficient.
1

There are three types of reduce methods. Try this code to understand it better

    /**
     * T reduce(T identity, BinaryOperator<T> accumulator)
     * 
     * identity = initial value
     * accumulator = first process initial value to first element of the stream,
     * then process the result with the next element in the stream
     */
     
    String name = Stream.of("T", "O", "M", "M", "Y")
            .reduce("", (a,n) -> a + n);
    System.out.println(name);
    
    int sum = Stream.of(1,2,3,4,5,6,7,8,9,10)
            .reduce(0, (a,n) -> a + n);
    System.out.println(sum);

    int multi = Stream.of(1,2,3,4,5,6,7,8,9,10)
            .reduce(1, (a,n) -> a * n);
    System.out.println(multi);
    
    
    /**
     * Optional<T> reduce(BinaryOperator<T> accumulator)
     * 
     */
    
    Optional<String> optName = Stream.of("T", "O", "M", "M", "Y")
            .reduce((a,n) -> a + n);
    
    if(optName.isPresent()){
        System.out.println(" get from optional --> " + optName.get());
    } 
    
    /**
     * <U> U reduce​(U identity, BiFunction<U,​? super T,​U> accumulator, BinaryOperator<U> combiner)
     * 
     * This method signature is used when we are dealing with different types.
     * It allows Java to create intermediate reductions and then combine them at the end.
     */
    
    int total = Stream.of("R", "a", "z", "v", "a", "n")
        .reduce(0, (a,b) -> a + b.length(), (x,y) -> x + y);
    
            // 0 = initial value type int
            // a = int, must match the identity type
            // b.method() return type must match the a and the identity type
            // x,y from BinaryOperator 
    
    System.out.println(total);
    
    
    String names[] = {"Bobby", "Mark", "Anthony", "Danna"};
    
    int sumAll = Stream.of(names)
            .reduce(0, (a,b) -> a + b.length(), (x,y) -> x + y);
    System.out.println(sumAll);
    
    String csvNames = Stream.of(names)
            .reduce("", (a,b) -> a + b + ";");
    System.out.println(csvNames);
    

3 Comments

Thank you very much. This is really helpful
The third one might be a little tricky but give it a try
The 3 argument example is pretty bad, since it would be better implemented using int total = Stream.of("R", "a", "z", "v", "a", "n").mapToInt(String::length).sum(). The 3 argument version isn't used just to do a map() operation, it is used when the result is truly a different type, e.g. a Collection object, or a stats object for gathering multiple results, such as min, max, and average.
0

I suggest you use the Stream.reduce() overload which expects two arguments:

  • identity: The identity element is both the initial value of the reduction and the default result if there are no elements in the stream
  • accumulator: The accumulator function which takes two parameters: a partial result of the reduction and the next element of the stream. It returns a new partial result.

Thus you will get your value using:

value = catalog
        .stream()
        .reduce(0L, (partialSum, nextElement) -> partialSum + nextElement.getUnitPrice() * nextElement.getUnitsInStore());

2 Comments

The Stream.reduce() method expects 1, 2, or 3 arguments, depending on which overload is used. The question is trying to use the 1 argument version. If you want, you might suggest using the 2 argument version instead, and explain why you're suggesting that, but that's not what this answer is doing, so it is not a useful answer.
That is correct. In my opinion, the best choice would be the one with 2 args, so OP can define the initial value. I will update the answer to clarify that one of the overloads expects two args

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.