I have a question regarding the usage of the Function.identity() method.
Imagine the following code:
Arrays.asList("a", "b", "c")
.stream()
.map(Function.identity()) // <- This,
.map(str -> str) // <- is the same as this.
.collect(Collectors.toMap(
Function.identity(), // <-- And this,
str -> str)); // <-- is the same as this.
Is there any reason why you should use Function.identity() instead of str->str (or vice versa). I think that the second option is more readable (a matter of taste of course). But, is there any "real" reason why one should be preferred?
As of the current JRE implementation, Function.identity() will always return the same instance while each occurrence of identifier -> identifier will not only create its own instance but even have a distinct implementation class. For more details, see here.
The reason is that the compiler generates a synthetic method holding the trivial body of that lambda expression (in the case of x->x, equivalent to return identifier;) and tell the runtime to create an implementation of the functional interface calling this method. So the runtime sees only different target methods and the current implementation does not analyze the methods to find out whether certain methods are equivalent.
So using Function.identity() instead of x -> x might save some memory but that shouldn’t drive your decision if you really think that x -> x is more readable than Function.identity().
You may also consider that when compiling with debug information enabled, the synthetic method will have a line debug attribute pointing to the source code line(s) holding the lambda expression, therefore you have a chance of finding the source of a particular Function instance while debugging. In contrast, when encountering the instance returned by Function.identity() during debugging an operation, you won’t know who has called that method and passed the instance to the operation.
In your example there is no big difference between str -> str and Function.identity() since internally it is simply t->t.
But sometimes we can't use Function.identity because we can't use a Function. Take a look here:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
this will compile fine
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
but if you try to compile
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
you will get compilation error since mapToInt expects ToIntFunction, which is not related to Function. Also ToIntFunction doesn't have identity() method.
From the JDK source:
static <T> Function<T, T> identity() {
return t -> t;
}
So, no, as long as it is syntactically correct.
Related
I have following expression that gets executed successfully:
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).andThen(x -> x+1).andThen(x -> x+2);
I understand why casting is required with the first lambda expression here. But following lambda gives error that "x+1" is not a valid operation for the second compose lambda expression
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).compose(x -> x+1).compose(x -> x+2);
I was able to resolve the above error using casting with compose:
Function<Long,Long> y = ((Function<Long,Long>)(x -> x*x)).compose((Function<Long,Long>)x -> x+1).compose(x -> x+2);
I have following questions:
Why do we need casting with compose calls but not with andThen
calls?
Why do we need casting with intermediate compose calls but not with
terminal compose calls?
Why do we need casting with compose calls but not with andThen calls?
The two methods are different. compose() takes a function whose input is of a type that is not necessarily the same as the current function's parameter type. Here's a slightly modified example to show that the compiler did not have to assume Long:
Function<Long, Long> f = (x -> x * x);
Function<String, Long> g = f.compose(Long::parseLong);
You can observe that f.compose() has a type argument of type String. In the above code, it's inferred from the assignment context (i.e., the compiler knows the input is String-typed because the resulting function is being assigned to a Function<String, Long> variable).
When it comes to .andThen(), however, things are simpler for the compiler : the type parameter <V> is for the output of the given function (not for the input, as is the case for compose). And because it already knows the input type, it has all the information: .andThen(x -> x+1) can only have Long as output type, because Long + int will produce long, boxed to Long. The end.
Why do we need casting with intermediate compose calls but not with terminal compose calls?
Now, think about it, what happens if I wrote this?
Function<String, Long> g = f.compose(Long::parseLong).compose(Long::parseLong);
What happens is that the compiler is ready to infer the <V> of the last .compose() to String because of the assignment context (see above). Question is: Should it assume String for the intermediate .compose()? The answer is Yes in this case* (because Long.parseLong only takes a string, there's no overload), but the compiler doesn't do that; it's a known limitation.
I can get it to work with f.<String>compose(Long::parseLong).compose(Long::parseLong); (which of course breaks my last .compose() call for obvious reasons, but you get the idea.
In other words, you can fix it with
A type witness
...<Long>compose(x -> x + 1).compose(x -> x + 2)
An explicit parameter type (my preferred option)
...compose((Long x) -> x + 1).compose(x -> x + 2)
*I say "yes in this case" because you cannot expect the compiler to always know the type. It's unambiguous here because Long.parseLong with a single parameter is not overloaded, so we can argue that the compiler could infer the intermediate .compose()'s <V> as <String>. But that should not be understood to mean that the compiler should be able to perform such inference in all situations. The function passed to .compose() could be one taking any other parameter type. The end to the discussion for now is that the compiler does not support this kind of inference.
The reason is the behavior of Function.compose and Function.andThen being non identical and non swappable.
If you run the following code.
Function<Long,Long> y1 = ((Function<Long,Long>)(x -> x*x)).andThen(x -> x+1).andThen(x -> x+2);
System.out.println(y1.apply(10l));
Function<Long,Long> y2 = ((Function<Long,Long>)(x -> x*x)).compose((Long x) -> x+1).compose(x -> x+2);
System.out.println(y2.apply(10l));
Even though we run both functions with same values (10) it returns different values. Where andThen is used it returns 103 (10x10+(1+2)) and where compose is used it returns 169 (10+1+2, 13x13). Thus compose is called before the multiplication lambda applies and compose gets a Function<Object, Long> as the parameter instead of Function<Long, Long> compose has no visibility as to any lambda that happened prior because it will be first to be called.
Since there is no context at the time calling compose we need to either cast to Function<Long, Long> or use type in the lambda itself as I have done. Hope this helps.
I have a small method containing the following code:
final int year = getYear();
final Carrier carrier = getCarrier();
final CarrierMetrics metrics = new CarrierMetrics(carrier);
repository.getFlightStream(year)
.filter(flight -> flight.getCarrier().equals(carrier))
.forEach(flight -> {
metrics.addFlight(flight);
printf("%,10d\t%,10d\t%,10d\t%,10d\r",
metrics.getTotalFlights(),
metrics.getTotalCancelled(),
metrics.getTotalDiverted(),
metrics.getAirports().size()
);
});
Hopefully it's obvious that what I am doing is accumulating metrics while processing each Flight in the stream. The code does work but I'm wondering if there is a better (more functional) way to implement this behavior, possibly using a Collector. Any feedback is appreciated.
Thanks,
-Tony
If the printing in the forEach is important,
then your current solution is good as it is.
forEach is designed for side effects,
and you have two side effects: adding metrics to CarrierMetrics instance and printing.
If the printing in the forEach is only for debugging,
and not intended in your final solution,
then a more functional implementation would be to collect results directly into a CarrierMetrics instance,
instead of initializing an instance first and manually adding with forEach.
You can use the overload of collect(...) that takes 3 arguments:
A Supplier<CarrierMetrics> to create an initial CarrierMetrics instance, which will be used as an accumulator
A BiConsumer<CarrierMetrics, Flight> that pass a Flight instance to the accumulator
The type Flight is just a guess based on the code you shared. It's the type of the stream (and so the type of the parameter of CarrierMetrics.addFlight method)
A BiConsumer<CarrierMetrics, CarrierMetrics> that combines multiple accumulators in case of a parallel stream
Like this:
final int year = getYear();
final CarrierMetrics metrics = repository.getFlightStream(year)
.filter(flight -> flight.getCarrier().equals(carrier))
.collect(CarrierMetrics::new, CarrierMetrics::addFlight, (a1, a2) -> {});
The third argument, the combiner, is a dummy,
you will need to fix that.
Its implementation should combine the two CarrierMetrics parameters into the first one.
(I cannot give a concrete example, because you haven't shared enough details about CarrierMetrics to be able to see how to do.
But to give some example, in case of a List accumulators,
the implementation could be (a1, a2) -> a1.addAll(a2).)
(Lastly, this example assumes that CarrierMetrics has a parameterless constructor, for the CarrierMetrics::new reference to work.
If there is no such constructor, you can use an appropriate lambda expression, such as () -> new CarrierMetrics(...).)
If CarrierMetrics exposing a addAll(List<Flight> flights) method you can do the following:
List<Flight> flights = repository.getFlightStream(year)
.filter(flight -> flight.getCarrier().equals(carrier))
.collect(Collectors.toList());
metrics.addAll(flights);
Can someone explain me, how come both of the lambdas can be replaced with method references here?
In RxJava, map() takes a parameter of type Func1<T, R>, whose comment states that it "Represents a function with one argument". Thus I completely understand why valueOf(Object) works here. But trim() takes no arguments at all.
So how does this work exactly?
Observable.just("")
.map(s -> String.valueOf(s)) //lambdas
.map(s -> s.trim()) //
.map(String::valueOf) //method references
.map(String::trim) //
.subscribe();
I didn't play with RX in java, but please note, that String::valueOf is a static (aka unbound) function, while String::trim is a non-static (aka bound) function that have indirect this argument. So, in fact, both function takes single argument. In Java it's not that visible as it is in Python for example.
I want to replace lambda expression by method reference in the below example :
public class Example {
public static void main(String[] args) {
List<String> words = Arrays.asList("toto.", "titi.", "other");
//lambda expression in the filter (predicate)
words.stream().filter(s -> s.endsWith(".")).forEach(System.out::println);
}
}
I want to write a something like this :
words.stream().filter(s::endsWith(".")).forEach(System.out::println);
is it possible to transform any lambda expression to method reference.
There is no way “to transform any lambda expression to method reference”, but you can implement a factory for a particular target type, if this serves recurring needs:
public static <A,B> Predicate<A> bind2nd(BiPredicate<A,B> p, B b) {
return a -> p.test(a, b);
}
with this, you can write
words.stream().filter(bind2nd(String::endsWith, ".")).forEach(System.out::println);
but actually, there’s no advantage. Technically, a lambda expression does exactly what you want, there’s the minimum necessary argument transformation code, expressed as the lambda expression’s body, compiled into a synthetic method and a method reference to that synthetic code. The syntax
s -> s.endsWith(".") also is already the smallest syntax possible to express that intent. I doubt that you can find a smaller construct that would still be compatible with the rest of the Java programming language.
You can use selectWith() from Eclipse Collections. selectWith() takes a Predicate2 which takes 2 parameters instead of a Predicate. The second parameter to selectWith() gets passed as the second parameter to the Predicate2 every time it's called, once per item in the iterable.
MutableList<String> words = Lists.mutable.with("toto.", "titi.", "other");
words.selectWith(String::endsWith, ".").each(System.out::println);
By default Eclipse Collections is eager, if you want to iterate lazily then you can use asLazy()
words.asLazy().selectWith(String::endsWith, ".").each(System.out::println);
If you can't change from List:
List<String> words = Arrays.asList("toto.", "titi.", "other");
ListAdapter.adapt(words).selectWith(String::endsWith, ".").each(System.out::println);
Eclipse Collections' RichIterable has several other *With methods which work well with method references, including rejectWith(), partitionWith(), detechWith(), anySatisfyWith(), allSatisfyWith(), noneSatisfyWith(), collectWith()
Note: I am a contributor to Eclipse Collections.
This code sample
Collection<Number> values = transform(
getValuatedObjects(),
input -> getValueProvider().apply(input).getValue());
violates the Sonarqube rule:
Lambdas should be replaced with method references
Is it a sonar bug?
Or can I really use a method reference?
You can’t replace the lambda input -> getValueProvider().apply(input).getValue() with a method reference without changing the semantics.
A method reference replace a single method invocation, so it can’t simply replace a lambda expression consisting of more than one method invocation.
A lambda expression of the form input -> getValueProvider().apply(input) could be replaced by getValueProvider()::apply if, and only if, the evaluation time of getValueProvider() does not matter as in the lambda form the method is invoked on each lambda body evaluation while for the method reference it is invoked only once and the result captured.
This is similar to the difference between x -> System.out.println(x) and System.out::println where reading the contents of the field System.out happens at different times but usually it doesn’t matter. But you should be aware of the difference.
In your example, a third method getValue() is invoked. The only way to express that with method references needs a functional interface like Function which has methods like andThen and/or compose. However, the way Java 8 works, that would require casting the first method reference to the target interface to invoke the combining method which would be by no way easier to read that the lambda expression you have now: ((Function<X,Y>)getValueProvider()::apply).andThen(Y::getValue) where Y is the type, apply(input) returns.
Note that the rule says “Replace lambdas with method references when possible” which gives you room to say, “well, here it is impossible”, however, I’m not sure how much you can call it a “rule” then…
list.stream().sorted().collect(Collectors.toList()).forEach(element ->
operate(element));
replace the above lambda with a method reference.
list.stream().sorted().collect(Collectors.toList()).forEach(this::operate);
if you are coding in java 8 you can use method reference in place of lambda expression for code readable
List<Integer> list = Arrays.asList(1,2,3,4,5);
replace this lambda with a method reference
strList.stream().sorted().collect(Collectors.toList()).forEach(s -> System.out.println(s));
Replace
strList.stream().sorted().collect(Collectors.toList()).forEach(System.out::println);
List<String> inputStringList = List.of("A", "B", "C", "D");
List<String> outputStringList = List.of("C", "D", "E", "F");
assertTrue(outputStringList.stream().anyMatch(inputStringList::contains));
assertTrue(outputStringList.stream().allMatch(inputStringList::contains));
This is a sample code to check if content of List is matching against another List using method reference.