Unable to understand lambdas AND longstream methods - java

I have such code example.
import java.util.LinkedList;
import java.util.List;
import java.util.stream.LongStream;
public class RemovedNumbers {
public static List<long[]> removNb(long n) {
System.out.println(n);
long sum = ((n + 1) * n / 2);
long minMultiplication = sum - 2 * n + 1;
long minCandidate = (long) Math.sqrt(minMultiplication);
LinkedList<long[]> list = new LinkedList<>();
LongStream.rangeClosed(minCandidate, n)
.mapToObj(a -> new long[]{a, calculateB(a, sum)})
.filter(longs -> longs[0] > longs[1])
.filter(longs -> longs[1] <= n)
.filter(longs -> longs[0] * longs[1] == sum - longs[0] - longs[1])
.forEach(longs -> addArrays(list, longs));
return list;
}
private static long calculateB(long a, long sum) {
return (sum - a) / (a + 1);
}
private static void addArrays(final LinkedList<long[]> list, final long[] longs) {
list.addFirst(new long[]{longs[1], longs[0]});
list.add(longs);
}
}
This code is complicated for me in LongStream part.
I don't get some points, so I need a help:
I examine LongStream class.
This class uses four methods: rangeClosed, mapToObj, filter, forEach (their description I found on Java docs). Unfortunately, now I am starting to examine java 1.8 version, so I can't understand how it works and what's happens.
Where is appeared "a" in mapToObj? What is it? I don't see var "a" declaration in previous part of code.
As I've got lambda is made by such scheme: (arguments) -> (body). So the "a" is an argument, "new long[]..." - is a body. This part isn't causes any question for me. But the next one, whereis "longs" - argument, "longs[0] > longs[1]" - body, causes some questions. What is the var "longs"? It hasn't declaration in the past! HOW it appears? How it works?
Am I right that LongStream class can be writes in one line? Like: LongStream.rangeClosed().filter().filter().filter().forEach(); ?
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order?
Thanks a lot!

Your third point kind of answers your second point - a is the parameter of the lambda expression passed to mapToObj.
If you can understand that, then your fourth point should be easy to understand as well. longs is the parameter for the lambda expression passed to filter. Remember that you can name your parameter names whatever you like. I guess the reason why the author of the code renamed the parameter to longs is because in the previous line, each long in the stream is mapped into a long[], so now it's a stream of long arrays.
Am I right that LongStream class can be writes in one line?
Yes, but you would end up with a super long line of code, so we almost never do that.
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order?
The methods get called in that order, but the operations they do won't run immediately. This is the cool part of streams. The longs will only be mapToObj'ed and filter'ed when you do forEach, a terminal operation. In other words, mapToObj and filter are kind of like saying "this is what this stream should do..." and when you do forEach, you are saying "now do it!"
If you still don't get what streams are doing, try to think of them as a production line in a factory. At the start, you have longs on the conveyer belts. And then they pass through a machine, transforming each of them into a long[]. After that, they pass through three filters. These filters will push them off the conveyer belt unless the long arrays fulfil some condition.
EDIT:
If you want to write this code without lambdas, you can write it with anonymous classes instead:
LongStream.rangeClosed(minCandidate, n)
.mapToObj(new LongFunction<long[]>() {
#Override
public long[] apply(long a) {
return new long[]{a, calculateB(a, sum)};
}
})
.filter(new Predicate<long[]>() {
#Override
public boolean test(long[] longs) {
return longs[0] > longs[1] &&
longs[1] <= n &&
longs[0] * longs[1] == sum - longs[0] - longs[1];
}
})
.forEach(new Consumer<long[]>() {
#Override
public void accept(long[] longs) {
addArrays(list, longs);
}
});

Each lambda expression implements a functional interface, or to be more specific, it implements the single abstract method of that functional interface.
Therefore, in a -> new long[]{a, calculateB(a, sum)}, a is the argument of the method implemented by the functional interface. Since mapToObj accepts an argument of type LongFunction, this lambda expression implements the R apply(long value) method of that interface, which means that lambda expression can also be written as (long a) -> new long[]{a, calculateB(a, sum)}.
This mapToObj call transforms the LongStream to a Stream<long[]>, so the lambda expression of the following filter call - longs -> longs[0] > longs[1] can also be written as (long[] longs) -> longs[0] > longs[1] - it implements the functional interface Predicate<long[]>, which means it implements boolean test(long[] t).
Yes, you can write this entire stream pipeline in a single line, but it would be more readable split into multiple lines.
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order
Not exactly. While each intermediate method produces an output used as input to the next method, the evaluation of these methods only begins once the terminal operation - forEach in this case - is executed. And these operations don't necessarily process all the elements of the Stream. For example, if the terminal operation would be firstFirst() instead of forEach, the pipeline would only process enough elements until the first element that passes all the filters is found.

Am I right that LongStream class can be writes in one line?
What you're witnessing here is method chaining. This is where method after method can get chained to eachother. This can be done for almost all classes.
Everything else is pretty much answered by Sweeper.

3 and 4:
you are tryng to understand how lambda work so I'll break it down your code for you:
// this return a LongStream obj
LongStream.rangeClosed(minCandidate, n)
// so with point notation you can access to one of the method in LongStream
// matToObj in this case.
.mapToObj(a -> new long[]{a, calculateB(a, sum)})
what is a? What ->? what the other stuff?
MapToObj takes a IntFunction mapper argument and a is a declaration of that type on the fly this is why you didin't see it before in the code.
the arrow indicates that the right site is the lamba expression, if you have a inline operation you can omit the return statement and you can not include {} brackets so imagine that statement like a return statement.
With lamba functions you can easily create chains of operation this is why you have many functions called one after another. You have to keep in mind that the next function takes as argument an object type that is of the same type of the return type of the previous function.

Related

How do you use a lambda expresion with complex math in java [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
hello i a trying to compare to values after i apply a lambda experrsion to them im trying to compare a location of a player and another to see the distance between them and im having trouble with lambdas
public class mathprob {
public static void main(String[] args) {
}
Location loc = player.getlocation();
Location newloc = player.getlocation();
(loc, newloc) -> Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-
newloc.getZ(),
2));
}
i keep getting a error because the lambda is incorrect i dont know how to use a lambda in this situation and then comparing the two values to each other (loc, newloc) the two values or two points P1(loc.getX(), loc,getY(), loc.getZ()) and P2(newloc.getX(), newloc.getY(), newloc.getZ()) i wanna compare the x and the y and the z of each point to see the number gap between them
Lambdas are just a way to create a type for a function. Keep in mind that a function has no "values" and hasn't been executed yet.
You can apply any Lambda to a set of values by calling it's apply method. It will then take the inputs (parameters to apply) and return the value as the result. A Lambda for a function that looks like this
(Coordinate x) -> { return new Distance(Math.sqrt(x.x * x.x + x.y * x.y)) }
would return the distance to the origin for a Coordinate assuming a Coordinate looked a little like
public class Coordinate {
public double x;
public double y;
}
and Distance looked a bit like like
public class Distance {
public Distance(double value) {
... whatever the implementation is ...
}
}
This function has a type conversion in it, it takes a Coordinate and returns a Distance. This means it fits the java "interface" of
Function<Coordinate, Distance>
and just by writing this Lambda
(Coordinate x) -> { return new Distance(Math.sqrt(x.x * x.x + x.y * x.y)) }
The Java compiler will generate some unnamed class of type Function<Coordinate, Distance> and instantiate an instance (create an object the class) to use in the context of the location of the Lambda.
Now if that lambda is within a method of a stream, such that the stream's parameter types are compatible, the stream will (in some manner) call apply on each value the stream is handling. Those values come from a Supplier which is basically an object that has a T get() method.
Stream calls the Supplier's get() method.
Stream has a method .forEach( ... ) containing a lambda that consumes the get() type.
Stream applies the value of get() to the lambda in forEach() by passing it into apply(value).
Stream collects the result of apply(value)
Stream returns from the .forEach(...) method a new stream with values typed to match the return value of the lambda in the forEach() method.
Eventually, these values are passed into a Collector method which combines values into some sort of buffer. Sometimes a List, sometimes a single value.
Conveniences exist for various ways of simplifying the collectors. Conveniences exist for generating values without coding suppliers.
The lambda syntax itself is a convenience for not having to write an implementation of one of the "xxxFunction" interfaces, create an object of it, and pass it into the stream.
Predicates are what they call Functions that return boolean values. There are even more convenience functions that work with predicates.
So, if you don't have a collection of data points to process, you probably shouldn't be using lambdas. If you do have a collection of data points to process, then keep in mind that streams and lambdas provide a new not-quite-like-a-loop way of processing them. They are guaranteed to be applied to all values, but the order of their application is not necessarily in the strong ordering that a traditional loop would apply. With the right options, you can effectively split the input into multiple chunks (spliterator vs iterator) and process the data in parallel.
Now that you have a quick overview of Lambdas, Streams, and the Functional interfaces, you can see that
(loc, newloc) -> Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-newloc.getZ(),
2));
wouldn't "do" anything, because at best it describes this
public class MyFunction implements Function<Location, Location, Double> {
Double apply(Location first, Location second) {
return Math.pow((first.getX()-second.getX()), 2)
+ Math.pow(first.getY()-second.getY(), 2)
+ Math.pow(first.getZ()-second.getZ(), 2)
}
}
MyFunction myFunc = new MyFunction();
Which has the following problem"
It's a coding error as it's only creating the facility to transform locations, and never using it.
Using the facility would look like
double result = myFunc.apply(loc, newloc);
Now, the very astute readers will mention auto-boxing, but in reality the compiler would choose the ToDoubleBiFunction type, probably side-stepping some of the possible auto-boxing issues. I just didn't want to write the example up in the non-generic manner, as again, the primitive functional types are a convenience (and optimization) of the general "all object" description above.
Lambda expressions are used to generate anonymous functions. They can be used where a #FunctionalInterface is expected.
Read more about them here: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
If you'd like your code to work you can assign your lambda to a BiFunction variable and then execute it passing in the loc and newloc.
public class mathprob {
public static void main(String[] args) {
Location _loc = player.getlocation();
Location _newloc = player.getlocation();
BiFunction<Location, Location, Double> lambdaExpression = (loc, newloc) -> {
return Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-newloc.getZ(),
2);
};
double result = lambdaExpression.apply(_loc, _newloc);
}
}
Here is an example of how the equivalent method declaration would look like instead of using a lambda:
public class mathprob {
public static void main(String[] args) {
Location loc = player.getlocation();
Location newloc = player.getlocation();
double result = calculate(loc, newloc);
}
public static double calculate(Location loc, Location newloc) {
return
Math.pow((loc.getX() - newloc.getX()), 2) +
Math.pow(loc.getY() - newloc.getY(), 2) +
Math.pow(loc.getZ() - newloc.getZ(), 2);
}
}
Read the 14.5. Statements from JLS.
value;
is not a valid statement, as
"text"; or 5; are not.
Lambda Expression is a value, which constitutes an anonymous method, and which can be assigned to the variable (of Functional Interface type) or can be passed into method, as an ordinary argument value.
public void someMethod() {
5; //does not compile, as this is not a statement.
int x = 5; //compiles, as this is a statement.
//Similarly,
() -> System.out.println("Hi"); //does not compile, as this is not a statement
Runnable r1 = () -> System.out.println("Hi"); //compiles, as this is a statement
}

How should I design this method in order to take a list of lambda expressions as an input?

I have the following assignment:
Design a class whose objects have the methods:
setValue which, given a String and an integer value, associates the value with the noun of the variable
getValue which returns the integer value associated with a given String
execute which invokes in sequence a given list of lambda expressions, where each one takes an instance of the class, return nothing, and act on the class through the methods setValue and getValue.
So for the example, after the following:
MyClass instance = new MyClass();
instance.execute(List.of(e -> e.setValue("x", 1),
e -> e.setValue("y", 2)));
instance should contain the values 1 for "x" and 2 for "y".
Here is what I've done so far, I think it's alright:
public class MyClass {
private Map<String,Integer> map;
public int getValue(String name) {return map.get(name);}
public void setValue(String name, int value) {map.put(name, value);}
I am not seeing the way to go for execute. I know I need a functional interface for those lambda expressions, but then I can't solve errors shown by Eclipse when writing instance.execute(List.of(...)) , e.g. "The method of(Object, Object) in the type List is not applicable for the arguments ((<no type> e) -> {}, (<no type> e) -> {}).
How can I make it work?
You need to supply a list of Consumer<MyClass>. A Consumer is a functional interface with a single abstract method called accept which performs the action on the the given argument. Try this.
public void execute(List<Consumer<MyClass>> list) {
list.forEach(cons -> cons.accept(this));
}
The problem with List::of is that you have to either use Java 9 or you can simply do this.
public void execute(Consumer<MyClass> ...list) {
Stream.of(list).forEach(cons -> cons.accept(this));
}
You have it backwards: If you want to call the method for a number of values, those values are the stream. Presuming you have a Map<String, Integer> that represents your "x": 1 dataset, you can do this:
valuesMap.entrySet().stream()
.forEach(entry -> instance.setValue(entry.getKey(), entry.getValue());
Given your problem statement, though, it looks like you're being asked to do something closer to the Visitor pattern. In this case, you need an interface for the lambdas to implement, and there's a built-in one: Consumer<MyClass>. You should get familiar with this one as well as Supplier and Function, since they're very common.
If you declare your execute method to take a list of these, then you can use a for loop or a stream to process them, or use the convenient built-in forEach method:
public void execute(List<Consumer<MyClass>> consumers) {
consumers.forEach(consumer -> consumer.accept(this));
}

Math.toIntExact inside lambda expression?

I'm learning about lambda expressions.
Given a list of names, I want to count the numbers of names that start with N.
I did that:
final static List<String> friends = Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
public static int countFriendsStartWithN() {
return Math.toIntExact(friends
.stream()
.filter(name -> name.startsWith("N"))
.count());
}
The call to the count method returns a primitive long but I want an int.
I used Math.toIntExact to get the long value as int.
Is it possible to get the int value directly inside the lambda expression?
No, it is not possible to fit your call to toIntExact into your chain of method calls, your stream pipeline. This is because count is a terminal operation and returns a primitive long on which no method call is possible. A terminal operation is an operation that ends the stream pipeline and produces a result (or a side effect).
So I believe the best thing you can do is to live with the code you already have. IMHO it’s fine.
Well, here's a somewhat silly way of calculating the count as an int without casting:
public static int countFriendsStartWithN() {
return friends.stream()
.filter(name -> name.startsWith("N"))
.mapToInt (s -> 1)
.sum();
}
You can't do anything inside the lambda expression you currently have, since that's a Predicate: it returns a boolean. Math.toIntExact returns an int.
You can do it without the Math.toIntExact (or a simple cast) like so:
return /* create stream, filter */
.mapToInt(a -> 1).sum();
But this is likely to be slower than doing what you are doing at the moment.
Yet another option that is not really better - it is possible to use a collector that applies a finisher:
public static int countFriendsStartWithN() {
return friends.stream()
.filter(name -> name.startsWith("N"))
.collect(Collectors.collectingAndThen(Collectors.counting(), Math::toIntExact));
}
This may have an advantage if you need it frequenty - you could build a utility method returning this Collector to make it reusable.
Here's a way to do this with reduce
public static int countFriendsStartWithN2() {
return friends
.stream()
.filter(name -> name.startsWith("N"))
.map(s -> 1)
.reduce(0, Integer::sum);
}

java 8 lambdas interface mismatch [duplicate]

I am confused by the following code
class LambdaTest {
public static void main(String[] args) {
Consumer<String> lambda1 = s -> {};
Function<String, String> lambda2 = s -> s;
Consumer<String> lambda3 = LambdaTest::consume; // but s -> s doesn't work!
Function<String, String> lambda4 = LambdaTest::consume;
}
static String consume(String s) { return s;}
}
I would have expected the assignment of lambda3 to fail as my consume method does not match the accept method in the Consumer Interface - the return types are different, String vs. void.
Moreover, I always thought that there is a one-to-one relationship between Lambda expressions and method references but this is clearly not the case as my example shows.
Could somebody explain to me what is happening here?
As Brian Goetz pointed out in a comment, the basis for the design decision was to allow adapting a method to a functional interface the same way you can call the method, i.e. you can call every value returning method and ignore the returned value.
When it comes to lambda expressions, things get a bit more complicated. There are two forms of lambda expressions, (args) -> expression and (args) -> { statements* }.
Whether the second form is void compatible, depends on the question whether no code path attempts to return a value, e.g. () -> { return ""; } is not void compatible, but expression compatible, whereas () -> {} or () -> { return; } are void compatible. Note that () -> { for(;;); } and () -> { throw new RuntimeException(); } are both, void compatible and value compatible, as they don’t complete normally and there’s no return statement.
The form (arg) -> expression is value compatible if the expression evaluates to a value. But there are also expressions, which are statements at the same time. These expressions may have a side effect and therefore can be written as stand-alone statement for producing the side effect only, ignoring the produced result. Similarly, the form (arg) -> expression can be void compatible, if the expression is also a statement.
An expression of the form s -> s can’t be void compatible as s is not a statement, i.e. you can’t write s -> { s; } either. On the other hand s -> s.toString() can be void compatible, because method invocations are statements. Similarly, s -> i++ can be void compatible as increments can be used as a statement, so s -> { i++; } is valid too. Of course, i has to be a field for this to work, not a local variable.
The Java Language Specification §14.8. Expression Statements lists all expressions which may be used as statements. Besides the already mentioned method invocations and increment/ decrement operators, it names assignments and class instance creation expressions, so s -> foo=s and s -> new WhatEver(s) are void compatible too.
As a side note, the form (arg) -> methodReturningVoid(arg) is the only expression form that is not value compatible.
consume(String) method matches Consumer<String> interface, because it consumes a String - the fact that it returns a value is irrelevant, as - in this case - it is simply ignored. (Because the Consumer interface does not expect any return value at all).
It must have been a design choice and basically a utility: imagine how many methods would have to be refactored or duplicated to match needs of functional interfaces like Consumer or even the very common Runnable. (Note that you can pass any method that consumes no parameters as a Runnable to an Executor, for example.)
Even methods like java.util.List#add(Object) return a value: boolean. Being unable to pass such method references just because that they return something (that is mostly irrelevant in many cases) would be rather annoying.

Why does a Java method reference with return type match the Consumer interface?

I am confused by the following code
class LambdaTest {
public static void main(String[] args) {
Consumer<String> lambda1 = s -> {};
Function<String, String> lambda2 = s -> s;
Consumer<String> lambda3 = LambdaTest::consume; // but s -> s doesn't work!
Function<String, String> lambda4 = LambdaTest::consume;
}
static String consume(String s) { return s;}
}
I would have expected the assignment of lambda3 to fail as my consume method does not match the accept method in the Consumer Interface - the return types are different, String vs. void.
Moreover, I always thought that there is a one-to-one relationship between Lambda expressions and method references but this is clearly not the case as my example shows.
Could somebody explain to me what is happening here?
As Brian Goetz pointed out in a comment, the basis for the design decision was to allow adapting a method to a functional interface the same way you can call the method, i.e. you can call every value returning method and ignore the returned value.
When it comes to lambda expressions, things get a bit more complicated. There are two forms of lambda expressions, (args) -> expression and (args) -> { statements* }.
Whether the second form is void compatible, depends on the question whether no code path attempts to return a value, e.g. () -> { return ""; } is not void compatible, but expression compatible, whereas () -> {} or () -> { return; } are void compatible. Note that () -> { for(;;); } and () -> { throw new RuntimeException(); } are both, void compatible and value compatible, as they don’t complete normally and there’s no return statement.
The form (arg) -> expression is value compatible if the expression evaluates to a value. But there are also expressions, which are statements at the same time. These expressions may have a side effect and therefore can be written as stand-alone statement for producing the side effect only, ignoring the produced result. Similarly, the form (arg) -> expression can be void compatible, if the expression is also a statement.
An expression of the form s -> s can’t be void compatible as s is not a statement, i.e. you can’t write s -> { s; } either. On the other hand s -> s.toString() can be void compatible, because method invocations are statements. Similarly, s -> i++ can be void compatible as increments can be used as a statement, so s -> { i++; } is valid too. Of course, i has to be a field for this to work, not a local variable.
The Java Language Specification §14.8. Expression Statements lists all expressions which may be used as statements. Besides the already mentioned method invocations and increment/ decrement operators, it names assignments and class instance creation expressions, so s -> foo=s and s -> new WhatEver(s) are void compatible too.
As a side note, the form (arg) -> methodReturningVoid(arg) is the only expression form that is not value compatible.
consume(String) method matches Consumer<String> interface, because it consumes a String - the fact that it returns a value is irrelevant, as - in this case - it is simply ignored. (Because the Consumer interface does not expect any return value at all).
It must have been a design choice and basically a utility: imagine how many methods would have to be refactored or duplicated to match needs of functional interfaces like Consumer or even the very common Runnable. (Note that you can pass any method that consumes no parameters as a Runnable to an Executor, for example.)
Even methods like java.util.List#add(Object) return a value: boolean. Being unable to pass such method references just because that they return something (that is mostly irrelevant in many cases) would be rather annoying.

Categories