2

I have created a Consumer which takes a string and makes it uppercase. I am trying to implement it along with a map to make all the strings in a list to uppercase. I understand that this can be done easily using String::toUpperCase but I am trying to do it with a Consumer and I am getting the following error

java: incompatible types: inferred type does not conform to upper bound(s)
    inferred: void
    upper bound(s): java.lang.Object

Here is my code

Consumer<String> upper = name -> name.toUpperCase();
names.stream().map(name -> upper.accept(name)).collect(Collectors.joining(" "))

I want to know if this is the correct way to use Consumer interface and also what would be a typical scenario where using Consumer would be helpful?

Holger
  • 285,553
  • 42
  • 434
  • 765

3 Answers3

1

Consumer will never work for Stream map operation. Stream map operation taking a Function as an argument. You can do this with following code also :

Function<String, String> upper = name -> name.toUpperCase();
names.stream().map(upper).collect(Collectors.joining(" "))
Sagar Zond
  • 39
  • 5
0

Consumer#accept returns nothing (void), so it will not compile, as Stream#map accepts a Function<? super T, ? extends R>. Instead of a Consumer, you can use a UnaryOperator<String> (which is a special Function<T, T>):

UnaryOperator<String> upper = String::toUpperCase;

names.stream()
     .map(upper)
     .collect(Collectors.joining(" "));

You also don't even need to store it in a local variable, as it can be inlined:

names.stream()
     .map(String::toUpperCase)
     .collect(Collectors.joining(" "));
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • I understand that I can use the toUpperCase but I wanted to know what would be the best use case of using a Consumer Interface? – Varun Upadhyay Feb 28 '18 at 01:34
  • That's too broad of a question for SO to answer. The answer to your first question, "I want to know if this is the correct way to use Consumer interface", is no. – Jacob G. Feb 28 '18 at 01:36
  • Ok thanks. I am able to do it now with the UnaryOperator – Varun Upadhyay Feb 28 '18 at 01:37
  • @VarunUpadhyay There is no "best use case" - that's like asking "what's the best use case for a screwdriver?" `Consumer` is a tool, which has multiple uses. A common use (based on open-source projects) is using `Consumer` (and/or other [functional interfaces](https://stackoverflow.com/questions/36881826/what-is-use-of-functional-interface-in-java-8/36882003)) to implement a [callback](https://en.m.wikipedia.org/wiki/Callback_(computer_programming)). – Vince Feb 28 '18 at 01:50
  • 1
    @VarunUpadhyay when you look at [the documentation](https://docs.oracle.com/javase/8/docs/api/?java/util/function/Consumer.html), you’ll find a [“USE” link](https://docs.oracle.com/javase/8/docs/api/java/util/function/class-use/Consumer.html) at the top. Clicking on it will show you, where you can pass a `Consumer` to a method. I suppose, the most often used example would be `.forEach(System.out::println)`… – Holger Feb 28 '18 at 08:29
0

Using a Consumer will never work, as you might expect it, because String.toUpperCase() returns a new instance of a String. Look at following example:

Consumer<String> toUpper = s -> {
    s.toUpperCase();
};

You see that nothing gets returned. And so the upper case string will be lost / discarded.

To do what you desire you have to use a Function which accepts a String and returns a String e.g:

Function<String, String> toUpper = String::toUpperCase;

With that you then can use the following statement:

Map<Key, String> map = ...;
map.entrySet().forEach(e -> {
    e.setValue(e.getKey(), toUpper.apply(e.getValue()));
}

To get what you intended in the first place.

Lino
  • 19,604
  • 6
  • 47
  • 65