Lambda reference to a field - java

I'd like to know how to get lambda reference to a field.
I don't want to use a method because my field is public final.
I suspect this is impossible but I don't see an obvious statement.
class A {
public final String id;
...
}
Map<String, A> f(List<A> l) {
return l.stream().collect(Collectors.toMap(A::id, Function.identity()));
}

It sounds like you're hoping that Java has a corresponding feature for field references as it does for method references. But this is not the case. Method references are shorthand for a certain category of lambda expressions, but there is no corresponding syntax for fields. Field literals were explored during the JSR-335 Expert Group deliberation (there is some reference to it here http://mail.openjdk.java.net/pipermail/lambda-dev/2011-November/004235.html) but were not included in Java SE 8.

You can always use a lambda expression:
return l.stream().collect(Collectors.toMap(a -> a.id, Function.identity()));
I think that "method references" are called this way for a reason, and therefore apply only for methods.

Related

Sonar compliant way to map Enum to Name

I have the below method to map various enums in my project to their name but sonar is complaining Code smell·Provide the parametrized type for this generic.
public static String mapToName(Enum customEnum) {
return Optional.ofNullable(customEnum).map(Enum::name).orElse("");
}
Its impossible to create separate mapToName method for tens of enums in my project, how do I make the above method sonar compliant?
First of all, please do not use Optional as replacement for if-else statements. They were not intended for that purpose. Optional was intended to convey the possibility of null-values in public interfaces in code, instead of just documentation, and only that. Even using optional in a private method is against it's intention (you're supposed to know what your own code does).
Please read this answer from one of the architects behind the Optional class: Should Java 8 getters return optional type?
As an excercise, you should go through the source code for Optional and count how many throwaway objects you create for each name mapping operation.
As for your problem, this is the correct way to solve the immediate Sonar complaint:
public static String mapToName(Enum<?> customEnum) {
return customEnum == null ? "" : customEnum.name();
}
The question mark is a wildcard which denotes an unknown type.
public static <T extends Enum<T>> String mapToName(Enum<T> customEnum) {
return Optional.ofNullable(customEnum).map(Enum::name).orElse("");
}
If you are pondering about the strange T extends Enum<T>:
Why in java enum is declared as Enum<E extends Enum<E>>

ModelMapping a Stream without a Lambda Expression

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.

Where is get() in Supplier interface implemented?

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);
}
});

Are reverse method references possible in Java 8?

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.

Replacing chained method call using method reference

"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.

Categories