I need to create some code like this:
this.getPendingDocuments()
.forEach((this::documentProcessed).andThen(this::createAuditory));
So I mean, I need to apply two functions to the same element.
Any ideas?
EDIT
Compiler tells me:
[Java] The target type of this expression must be a functional interface
You can write a lambda expression that executes both methods:
this.getPendingDocuments()
.forEach(doc -> {
this.documentProcessed(doc);
this.createAuditory(doc);
});
When you use forEach() you can add more functions inside... like this
this.getPendingDocuments()
.forEach( element -> {
this.documentProcessed(element);
this.createAuditory(element);
});
You must target your method references to a functional interface type. In this case, forEach requires a Consumer instance:
Consumer<Document> processDocument = this::documentProcessed;
this.getPendingDocuments().forEach(processDocument.andThen(this::createAuditory));
The code above uses Consumer.andThen to chain consumers. Of course, both methods should accept a Document instance as an argument (or whatever the type of the elements of the Iterable returned by the getPendingDocuments() method is).
Related
I'm sure this is answered somewhere, but I don't have good enough search terms to find it. I am using the io.vavr.control.Try package, and when I try to use getOrElseThrow method on an element in a stream of results, the method is ambiguous with the io.vavr.Value class. Can I specify which method I want to use somehow, or is it impossible?
You have a number of options:
Add an explicit cast to the desired type:
.map(rsp -> rsp.getOrElseThrow((Supplier<NotFoundException>) NotFoundException::new))
.map(rsp -> rsp.getOrElseThrow((Function<? super Throwable, NotFoundException>) NotFoundException::new))
Use a lambda expression instead of a method reference:
.map(rsp -> rsp.getOrElseThrow(() -> new NotFoundException()))
.map(rsp -> rsp.getOrElseThrow(t -> new NotFoundException(t)))
Use an explicit type of the outer lambda parameter:
.map((Value<…> rsp) -> rsp.getOrElseThrow(NotFoundException::new))
.map((Try<…> rsp) -> rsp.getOrElseThrow(NotFoundException::new))
You could replace NotFoundException::new with t -> new NotFoundException(t) which will only match the Function argument.
Since you didn't post complete code I can only make an educated guess about how your NotFoundException looks like, but I think it contains at least two constructors in the following form:
public NotFoundException() {}
public NotFoundException(Throwable cause) {
super(cause);
}
If you want to use constructor method references with Try.getOrElseThrow, you'll need to eliminate the method reference ambiguity by removing one of these constructors (or potentially reducing visibility), or fall back to using lambdas for constructing the resulting throwable.
If you cannot, or do not want to change the NotFoundException class, you can either fall back to using a lambda instead of a method reference (1 and 2), or you can create explicit Function(2) or Consumer(3) instances with the help of the vavr function type factory methods:
rsp.getOrElseThrow(cause -> new NotFoundException(cause)); // (1)
rsp.getOrElseThrow(() -> new NotFoundException()); // (2)
rsp.getOrElseThrow(Function1.of(NotFoundException::new)); // (3)
rsp.getOrElseThrow(Function0.of(NotFoundException::new)); // (4)
I'm not Java developer, but I have many years of experience in C#. I have a List<Foo> that I need to convert to a List<Bar> using ModelMapper where Foo and Bar have essentially identical properties.
Currently I've written this as:
#AutoWired ModelMapper modelMapper;
...
List<Bar> results = repository
.getFoos()
.stream()
.map(x -> modelMapper.map(x, Bar.class))
.collect(Collectors.toList());
This works fine. However, I feel like that lambda expression could be replaced with just a simple method reference. If this were C#, I'd probably be able to do something along the lines of this:
var results = repository.getFoos().Select(modelMapper.map<Bar>).ToList();
But I can't find the right syntax in Java. I've tried this:
.map(modelMapper::<Bar>map)
But I get the error:
Cannot resolve method 'map'
I am not sure if this is because I've mixed up the syntax somehow, or this is because the map method has a too many overloads to create an unambiguous reference. In case it helps, the overload of map that I'm trying to use is defined as:
public <D> D map(Object source, Class<D> destinationType)
Is there any way to achieve this mapping without a lambda expression?
I am not sure if this is because I've mixed up the syntax somehow, or this is because the map method has a too many overloads to create an unambiguous reference.
You've not messed up the syntax; there's no equivalent in Java (it's often more verbose than C#, and streams are no exception.)
You can only use the method reference (double colon) syntax when the parameters you want to pass to the method are the same, and in the same order, as the parameters in the functional interface.
In the case of map, there's only one parameter, and you need to pass a second parameter (that being Bar.class) to modelMapper.map(), so no method reference syntax is allowed. The only way you could use it were if you were to subclass the modelMapper to work with Bar only, and therefore remove the need for the second explicit class parameter.
I'm pretty confident that the method you're using there is the most concise way of doing things in Java.
Java doesn't support partial function application (related to currying), so you can only do that with a lambda.
Of course, since you don't reference any local variables or parameters, you can define a method which you can then reference.
#AutoWired ModelMapper modelMapper;
private Bar mapToBar(Foo x) {
return modelMapper.map(x, Bar.class);
}
...
List<Bar> results = repository
.getFoos()
.stream()
.map(this::mapToBar)
.collect(Collectors.toList());
That is actually very close to how the lambda is compiled, except that mapToBar for the lambda would be a hidden (synthetic) method.
Actually this can not be done, because your modelMapper.map() method requires two parameters. If you really want to use method reference at this point you could create a new method in your modelMapper, which requires only one parameter or wrap the modelMapper.map() call in another method like this:
private Bar mapFooToBar(Foo x) {
return modelMapper.map(x, Bar.class);
}
You now can use this method with method reference:
List<Bar> results = repository.getFoos().stream()
.map(this::mapFooToBar)
.collect(Collectors.toList());
But at the end I don't think that this will make your code better in any way, so I would recommend using the lambda expression you already have.
I have this piece of code
public <T> someMethod(Supplier<T> supplier) {
Objects.requireNonNull(supplier);
SupplierThrowsException<T, Throwable> supplierThrowsException = supplier::get;
return withThrowable(supplierThrowsException);
}
I am calling it like this
obj.someMethod(() -> myMethod(message))
I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface. So where is the implementation of get().
I went through the Javadoc, I didn't get anything. I would like to understand what's going on here.
I found this and this but it doesn't clear my doubt. Let me know if I am missing anything here.
I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface.
Sure, but the expression () -> myMethod(message) does.
Please, read 15.27.4. Run-Time Evaluation of Lambda Expressions.
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.
The value of a lambda expression is a reference to an instance of a class with the following properties:
The class implements the targeted functional interface type and, if the target type is an intersection type, every other interface type mentioned in the intersection.
In short, the lambda expression () -> myMethod(message) will be resolved to an instance of Supplier.
Where is the implementation of get()?
You've provided it within the lambda body.
() -> myMethod(message)
(it's a statement expression, a shorter form to construct a lambda body)
() -> {
return myMethod();
}
(it's a value-compatible block, a more expanded version where many statements may be declared)
In this call:
obj.someMethod(() -> myMethod(message))
you are implementing the Supplier interface using a lambda expression - () -> myMethod(message).
It is as if (I say "as if" because this is not what actually happens under the hood. Here is what happens under the hood) you have created an inner class implementing Supplier like this:
static class MyInnerClass implements Supplier<SomeClass> {
public SomeClass get() {
return myMethod(message);
}
}
And then passed new MyInnerClass() to someMethod.
I think this document may shed some light on your question:
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#target-typing
To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type:
Variable declarations
Assignments
Return statements
Array initializers
Method or constructor arguments
Lambda expression bodies
Conditional expressions, ?:
Cast expressions
Supplier is a functional interface and contains following single abstract method:
#FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* #return a result
*/
T get();
}
Now, you have provided definition of get method along with instantiation with following invocation:
obj.someMethod(() -> myMethod(message))
Above line gets translated as follows:
obj.someMethod(new Supplier() {
#Override
public T get()
{
return myMethod(message);
}
});
I know about lambda method references.
However, I am wondering whether the reverse might be possible, because I have a method that just proxies its arguments to a lambda:
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
Haven't found anything on Google, so I guess it's not possible. Which makes sense, because after all, as I understand it, a lambda is just shorthand for a whole interface. A method and an interface are different. But you can make a lambda from a method, so maybe you can make a method from a lambda?
You can't make a method from a lambda because, as you say, a lambda is not a method and more importantly you cannot dynamically change a class by adding methods to it at runtime. That's a basic design invariant of Java classes. It is possible to dynamically respond to a predefined method of an interface with your own implementation, although it's fairly clunky. Take a look at http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
The variable lambda has the type Function which doesn’t say anything about how the instance has been created. It might be a lambda expression, but it doesn’t have to. That said, if you want to delegate myMethod to a method declared in Function, there is no reason to automatically choose the abstract method of that interface, so, similar to method references, you would have to specify the target method like lambda::apply to make clear you want that method and not one of the other methods of the interface Function.
But unlike method references, which use a target type, you can’t derive a method declaration from the surrounding context, so you can’t spare the method declaration. So such a hypothetical feature would still require the method declaration, the reference to the lambda field and the target method name (apply), so there is not much left that you can save that would justify a new language feature.
And there is no need for such a functionality anyway. If you have code to be expressed as both, a function and a method, express it as method:
Instead of
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
write
Function<Arg, Result> lambda = this::myMethod;
public Result myMethod(Arg arg) {
return new Result(arg);
}
But even a code replication might be acceptable, as in
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return new Result(arg);
}
considering that lambda expressions should host rather small, often trivial, code only.
"Java 8 Lambdas: Pragmatic Functional Programming" has an example for using peek method in Stream API. This piece of code prints artist nationalities whose name starts with "The":
Set<Nationality> nationalities = album.getMusician()
.filter(artist -> artist.getName().startsWith("The"))
.map(artist -> artist.getNationality())
.peek(nation -> System.out.println(nation))
.collect(Collectors.toList());
I want to rewrite this code with method references:
Set<Nationality> nationalities = album.getMusician()
.filter(artist -> artist.getName().startsWith("The"))
.map(Artist::getNationality)
.peek(System.out::println)
.collect(Collectors.toList());
Is there any solution to rewrite filter(artist -> artist.getName().startsWith("The"))?
You need to create a separate method that takes an Artist and returns a boolean:
private boolean nameStartsWithThe(Artist a) {
return a.getName().startsWith("The");
}
Set<Nationality> nationalities = album.getMusician()
.filter(this::nameStartsWithThe)
or with a static method:
private static boolean nameStartsWithThe(Artist a) {
return a.getName().startsWith("The");
}
Set<Nationality> nationalities = album.getMusician()
.filter(MyClass::nameStartsWithThe)
You'd need something that composes the two methods. There are some methods for composing methods (IntUnaryOperator has compose and andThen methods that can compose two IntUnaryOperators into a new IntUnaryOperator). But the ones I've found all seem specialized for certain types of functional interfaces; defining compose methods for every possible pair of functional interface types would be too unwieldy.
I did get something to work that would compose a Function and a Predicate to get a new Predicate:
static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
return obj -> pred.test(func.apply(obj));
}
That is, it can compose a predicate that operates on T from a function that takes a T and returns U, and a predicate that operates on U. This would almost work on your example, except that startsWith needs another parameter. But this does work:
static boolean startsWithThe(String s) {
return s.startsWith("The");
}
Predicate<Artist> pred = functionPredicate(Artist::getName, ThisClass::startsWithThe);
where ThisClass is whatever class contains startsWithThe. This works. If you want to avoid writing a new method (like startsWithThe), you could probably write a "parameterized predicate" generic method so that you write something like
Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));
but I haven't tried it.
So it seems it's possible to come up with something that will let you use method references instead of lambdas. I question whether it's worthwhile. To me, a method reference is just a shorthand for certain kinds of lambdas; and unless you can do what you want with a simple method reference, I'd think using a lambda is concise and clear enough, and you don't need to add all the extra rigmarole like my functionPredicate method. I've seen several questions that ask something like "How can I use a method reference for this instead of a lambda?", and I honestly don't understand why.
There is no way to replace that line with a method reference.
Method reference works by using the fact that there is only one object being used in entire lambda expression and the compiler can infer it (reference does not matter and type can be inferred) using target typing.
So,
artist -> artist.getNationality()
is replaced with
Artist::getNationality
Here Artist::getNationality method matches with the target type without requiring any further information.
In case of artist -> artist.getName().startsWith("The"), there are two method calls in the lambda expression. The order, parameters are important, and have to be specified.
It looks as if the artist reference should be inferred, but the compiler won't know what object should the startsWith("The") method be called on.
Hope this helps.