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.
Related
kotlin 1.3.31
I have the following code snippet in Java that I am trying to convert to Kotlin
private ArgumentMatcher<List<Person> customArgumentMatcher(final int size) {
return argument -> argument.size() == size;
}
My understanding of the above is a method declaration that has a ArgumentMatcher as the return type and the method of the interface is executed in the lambda expression and the resulting boolean is returned. Correct me if I am wrong with my explanation.
However, when I try and convert this to Kotlin
private fun customArgumentMatcher(size: Int): ArgumentMatcher<List<Person>> {
return { argument -> argument.size == size }
}
I get the following error:
Required ArgumentMatcher<List<Person>>
found: (???) -> Boolean
Many thanks for any suggestions,
Since ArgumentMatcher is a Java functional interface you need to use:
fun customArgumentMatcher(size: Int): ArgumentMatcher<List<Person>> {
return ArgumentMatcher { argument -> argument.size == size }
}
See the SAM Conversions section of the Kotlin reference.
You could also use:
fun customArgumentMatcher(size: Int) = ArgumentMatcher<List<Person>> { it.size == size }
See gidds' answer for some background on why the above syntax is necessary.
To add some background to the other answer:
This is one of the slightly awkward areas in Kotlin, as far as Java interoperability goes. But it's an unfortunate consequence of Kotlin being a better language in itself! Let me try to explain…
When Java added lambdas, they did it in a way (as with generics before that) to make the bare minimum of changes to the way the language worked. So they didn't make functions first-class types. Instead, they enshrined the existing practice of using interfaces. For example, if you wanted something to be informed of ActionEvents, you'd implement the ActionListener interface. This has a single method called actionPerformed() taking an ActionEvent parameter.
They didn't want to change how any of that worked, so in Java 8+, a lambda is simply a more concise way of implementing some interface. The context (i.e. the method you're calling, or the type of variable you're assigning it to) tells the compiler what type of interface you want — it must be a ‘functional interface’ with a Single Abstract Method (SAM) — and then the compiler generates an implementation. There are a few optimisations, but it's basically what you used to do in Java 7-. It doesn't work too badly, but there are a lot of awkward corner cases, because functions aren't full first-class objects.
Kotlin, on the other, does have proper function types. This is much more powerful and flexible, but doesn't match Java's way of doing things.
The Kotlin compiler has some special cases allowing a lambda to be automatically converted into an implementation of a Java SAM interface. (This doesn't apply when implement Kotlin interfaces, though, which causes some confusion.)
In cases where you're passing a SAM-implementing lambda directly to a method, the compiler can infer its type. (As in #Slaw's second example.)
But in other cases, you need to specify the interface name before the opening brace. (As in #Slaw's first example.)
EDIT: The method I'm testing calls this constant that's defined in another class, so I want to test that th emethod works independently of how the other class defines the constant. Mocking it was the first thing I could think of, but I'm open to other ideas for how to test it in a clean, secure way
(Class, method, and variable names are genericized)
I'm trying to figure out how to write a test.
One of my methods gets a constant from another class, like so:
OtherClass.CONSTANT
and this constant is defined as:
public static final List<Long> CONSTANT =
ImmutableList.of(1, 2);
In the test for this method, I want to mock this call. I've tried
when(OtherClass.CONSTANT).thenReturn(ImmutableList.of(1, 2));
but that gives me this error:
RegularImmutableList cannot be returned by otherFunction()
otherFunction() should return String
otherFunction() being some other function in the code base that doesn't seem to be related to anything I've been working on.
I've also tried
doReturn(ImmutableList.of(1, 2)).when(OtherClass.CONSTANT);
but, as you might be guessing, it gives me this error:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
I'm pretty lost as to how exactly I should be mocking this constant.
As you've discovered, you can't mock the value of a constant.
Likely the easiest method would be to convert your design to use an interface to supply the value, rather than using the value directly.
Something like:
interface ConstantSupplier {
List<Long> get();
}
public MyClass(ConstantSupplier supplier) {
this.supplier = supplier;
}
Then you would replace references to the constant to supplier.get().
This is now easy to mock:
ConstantSupplier supplier = mock(ConstantSupplier.class);
when(supplier.get()).thenReturn(List.of(4L, 9L));
Your non-mocked code could use a lambda to supply the real value:
obj = new MyClass(() -> OtherClass.CONSTANT);
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.
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.
"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.