Shorten nested lambda - java

I want to map a list of tasks to List<Callable<Tasks>>:
List<Callable<Tasks>> callableTasks = tasks.stream().map(t ->
{
// how to return callable directly and omitting curly braces?
Callable<Task> task = () -> run(t);
return task;
}).collect(Collectors.toList());
How can I shorten the above expression to return the callable directly?

You can use static methods from Executors class, for example Executors.callable:
tasks.stream().map(t -> callable(() -> run(t))).collect(Collectors.toList());

The problem is that the lambda expression () -> run(t) requires a target type.
In a construct like
List<Callable<Tasks>> callableTasks = tasks.stream()
.map(…).collect(Collectors.toList());
The assignment to List<Callable<Tasks>> callableTasks provides a target type to the collect method invocation, but can’t propagate it to the preceding map invocation (a general limitation of Java’s current type inference).
By splitting the mapping function into an assignment and a return statement, you are providing a target type. Likewise, you could provide target type by casting, e.g. .map(t -> (Callable<Task>)() -> run(t)) or by providing an explicit type for the generic method map, e.g. .<Callable<Task>>map(t -> () -> run(t)).
The latter solution leads to
List<Callable<Task>> callableTasks = tasks.stream()
.<Callable<Task>>map(t -> () -> run(t)).collect(Collectors.toList());
If the Task instance returned by run(t) is the same as passed to it as argument, you can use Executors.callable like:
List<Callable<Task>> callableTasks = tasks.stream()
.map(t -> Executors.callable(() -> run(t), t)).collect(Collectors.toList());
Note the Executors.callable encapsulates a Runnable, which provides no return value. So the constructed Callable will evaluate to the result specified to Executors.callable as second argument or to null if you use the one argument version.

Related

Java8 stream cannot resolve a variable

I am new in Java8 and I want to refactor this piece of code and convert it in a more Java8 style,
for (RestaurantAddressee RestaurantAddressee : consultationRestaurant.getAddressees()) {
Chain chain = chainRestService.getClient().getChainDetails(getTDKUser(), RestaurantAddressee.getChain().getId());
if (chain.getOrganisation().getId().equalsIgnoreCase(event.getOrganisationId())) {
chainIds.add(restaurantAddressee.getChain().getId());
}
}
so I change it for this code:
consultationRestaurant.getAddressees()
.stream()
.map( ma -> chainRestService.getClient().getChainDetails(getTDKUser(), ma.getChain().getId()))
.filter(chain -> chain.getOrganisation().getId().equalsIgnoreCase(event.getOrganisationId()))
.forEach(chainIds.add(chain.getId()));
But I have this compilation error:
chain cannot be resolved
You forgot to specify the lambda expression parameter in your forEach call.
That said, you shouldn't use forEach to add elements to a collection. Use collect:
List<String> chainIds =
consultationRestaurant.getAddressees()
.stream()
.map( ma -> chainRestService.getClient().getChainDetails(getTDKUser(), ma.getChain().getId()))
.filter(chain -> chain.getOrganisation().getId().equalsIgnoreCase(event.getOrganisationId()))
.map(Chain::getId)
.collect(Collectors.toList());
Here. Your loop defines:
Chain chain = chainRestService.getClient()...
But your stream statement simply misses to define that variable.
So: in places that need that variable, you have to provide, for example as parameter:
filter(chain -> chain.getOrganisation().getId().equalsIgnoreCase(event.getOrganisationId()))

Enums Returning Arrays Stream

I have a requirement to validate a field against some predefined values (that can grow in future). So for this I have created a Enum and defined a method that returns the stream of the allowed values.
public enum EnumDemo {
VERSION("1.0.0","2.0.3");
private List<String> ver;
EnumDemo(String... ver) {
this.ver = Arrays.asList(ver);
}
public List<String> getVer() {
return ver;
}
public static Stream<EnumDemo> stream() {
return Arrays.stream(EnumDemo.values());
}
}
Now I need to validate a field against the values defined in this Enum.
I'm using:
Optional<EnumDemo> ab = EnumDemo.stream()
.map(l -> {l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst();})
.findFirst();
System.out.println(ab.get().getVer());
But it is giving me compilation error. Any help would be appreciated.
Edit:
Compilation Error:
The method map(Function<? super EnumDemo,? extends R>) in the type Stream<EnumDemo> is not applicable for the arguments ((<no type> l) -> {})
You should write it this way:
Optional<EnumDemo> ab = EnumDemo.stream().filter(l -> l.getVer().contains("2.0.3"))
.findFirst();
By the way, it wasn't working because you used {} for the lambda expression, so it was expecting a return statement in the {}. You could either remove the {} (along with the ;) or add in the return.
Anyway the original codes looked confusing, not sure if I guessed the intention correctly, but this implementation should be clearer.
Edit
Based on your comment, this is what you need:
EnumDemo.stream().flatMap(l -> l.getVer().stream())
.filter("2.0.3"::equals)
.findAny()
.ifPresent(System.out::println);
Update
Holger commented that there is a shorter and more meaningful way, with better performance:
if(EnumDemo.stream()
.anyMatch(l -> l.getVer().contains(userString))) {
System.out.println(userString);
}
To understand it, you have to think about lambdas. Lambdas represent interfaces but are specially treated by the JVM, so not every Lambda needs a class to represent. (Stateless lambdas can be just methods).
Now when looking at the map() method in the Stream interface:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
You see that it expects an implementation of the Function interface. You now have many different ways to provide that mapper. In this example lets map from Object to String:
1. Using an inline lambda:
.map(o -> o.toString())
2. Using a multiline lambda:
.map(o -> {
return o.toString();
})
3. Using method references:
.map(Object::toString)
4. Using an anonymous class:
.map(new Function<Object, String>(){
#Override
public String apply(Object o){
return o.toString();
}
})
Your current code uses the 2. approach. But without a return statement. This is even better seen when looking at the anonymous class at 4.. It seems natural, that when not using a return statement in a method that no value is returned.
And that's why you get the compilation error.
You just have to add the return statement:
.map(l -> {
return l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst();
});
Or remove the brackets {}:
.map(l -> l.getVer().stream()
.filter(c -> c.equals("2.0.3"))
.findFirst());
Or even use the approach provided by #Jai in his answer. Which works even better, than what you currently have.
You are using lambda expression and not returning any value so it is giving compilation error. It is better to use ifPresent()
String val="2.0.3";
EnumDemo.stream()
.flatMap(l -> l.getVer().stream())
.filter(c -> c.equals(val))
.findAny()
.ifPresent(x -> System.out.println(x));

Better way to create a stream of functions?

I wish to do lazy evaluation on a list of functions I've defined as follows;
Optional<Output> output = Stream.<Function<Input, Optional<Output>>> of(
classA::eval, classB::eval, classC::eval)
.map(f -> f.apply(input))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
where as you see, each class (a, b & c) has an Optional<Output> eval(Input in) method defined. If I try to do
Stream.of(...)....
ignoring explicit type, it gives
T is not a functional interface
compilation error. Not accepting functional interface type for T generic type in .of(T... values)
Is there a snappier way of creating a stream of these functions? I hate to explicitly define of method with Function and its in-out types. Wouldn't it work in a more generic manner?
This issue stems from the topic of the following question;
Lambda Expression and generic method
You can break it into two lines:
Stream<Function<Input, Optional<Output>>> stream = Stream
.of(classA::eval, classB::eval, classC::eval);
Optional<Output> out = stream.map(f -> f.apply(input))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
or use casting:
Optional<Output> out = Stream.of(
(<Function<Input, Optional<Output>>>)classA::eval,
classB::eval,
classC::eval)
.map(f -> f.apply(input))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
but I don't think you can avoid specifying the type of the Stream element - Function<Input, Optional<Output>> - somewhere, since otherwise the compiler can't infer it from the method references.
There is a way that allows to omit the Function<Input, Optional<Output>> type, but it’s not necessarily an improvement
Optional<Output> o =
Stream.concat(Stream.of(input).map(classA::eval),
Stream.concat(Stream.of(input).map(classB::eval),
Stream.of(input).map(classC::eval)))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
and it doesn’t scale.
It seems, the best option is to wait for Java-9 where you can use
Optional<Output> o = classA.eval(input)
.or(() -> classB.eval(input))
.or(() -> classC.eval(input));

Java 8 predicate to select the max

This is a two-part question. I'm just learning about predicates in Java 8 and I need to know if there is a predicate that I can pass to the filter() method to select the max in a list of integers, as below:
List<Integer> numbers = ...
Integer max = numbers.stream()
.filter(n -> ???)
.getFirst()
.get();
The bigger question is: can predicates be chained mathematically so that one doesn't have to chain filter() or reduce() methods, such that the work done in one predicate can be reflected in or passed to the following one, so instead of writing:
list.stream()
.filter(/* predicate1 */
item -> {
// do some work and save in some local variable "var"
})
.filter(/* predicate2 */ var -> ...)
.reduce(predicate3)
.getFirst()
.get();
I could write:
list.stream()
.filter(predicate1 "andThen" predicate2 "andThen" reduce by predicate3)
.getFirst()
.get();
I speculate that there might be a way using the andThen() functionality or writing a custom predicate. Can anyone help me understand this better?
No, you cannot use filter(Predicate) to select the maximum value of a Stream.
You have multiple other options:
stream.max(Comparator.naturalOrder());
stream.sorted(Comparator.reverseOrder()).findFirst();
stream.mapToInt(i -> i).max();
stream.reduce(Integer::max);
Yes, Predicates can be chained by and(Predicate). The implementation basically looks like this:
Predicate<T> and(Predicate<? super T> other) {
return t -> test(t) && other.test(t);
}
You could also simply write your own:
static <T> Predicate<T> and(Predicate<? super T>... ps) {
return t -> Stream.of(ps).allMatch(p -> p.test(t));
}
Usage:
stream.filter(and(i -> i > 11, i -> i < 50))
You can apply multiple filters, so you usually chain the calls:
stream.filter(i -> i > 11).filter(i -> i < 50)
Do you understand what reduce(BinaryOperator) does? You cannot put a Predicate in there.
I have already used it above as an option to get the maximum value.

Wrong object's type after possible return of empty stream

I have written following code:
Set<Pair<Predicate>> interestingPairs = ...
...
interestingPairs.stream()
.filter(pair -> pair.getFirst().isNegated() == pair.getSecond().isNegated())
.flatMap( pair -> findUnification(pair)
.map(u -> {
Set<String> aVars = pair.getFirst().getAllVariables();
Set<String> bVars = pair.getSecond().getAllVariables();
if(u.sigma.isEmptyOrVarByVar(aVars) && !u.sigmaPrime.isEmptyOrVarByVar(bVars))
return Stream.of(pair.getFirst());
if (!u.sigma.isEmptyOrVarByVar(bVars) && u.sigmaPrime.isEmptyOrVarByVar(aVars))
return Stream.of(pair.getSecond());
return Stream.empty();
})
.orElse(Stream.empty()))
.forEach(toRemove -> this.predicates.remove((Predicate)toRemove));
I'm using intelliJ IDE. After flatMap operation elements of my stream have Object type instead of Predicate, so in the foreach toRemove has not desired type. When I change return Stream.empty() to return Stream.<Predicate>empty(), object's type after flatMap is Predicate. I would even understand this if not .orElse(Stream.empty()) where I don't have to add the <Predicate implicitly. What's the thing I don't get here?
I assume that your Predicate is your custom non-generic type, not the java.util.function.Predicate. Seems that the compiler fails to infer the type of the .flatMap argument. You may help it specifying it explicitly:
interestingPairs.stream()
.filter(pair -> pair.getFirst().isNegated() == pair.getSecond().isNegated())
.<Predicate>flatMap( pair -> findUnification(pair)
... and so on
To my understanding, current JLS automatic type inference rules do not cover this case, so it's not a compiler bug. You just have to specify type argument explicitly sometimes or extract some complex lambdas to intermediate variables.

Categories