When to know if I can use double colon with lambda? - java

Of the following lines, why is the first and last allowed ?
List<String> l = new ArrayList<>();
l.stream().forEach(System.out::println);//compiles
l.stream().forEach(System.out.println(String::compareTo));//doesnt compile
l.stream().forEach(String::compareTo);// doesnt compile
String comparedWith = "";
l.stream().forEach(comparedWith::compareTo);//compiles why ?
edit
If compareTo takes one argument, shouldn't it work also ?
If according to docs:
Represents an operation that accepts a single input argument and
returns no result. Unlike most other functional interfaces, {#code
Consumer} is expected to operate via side-effects.

l.stream().forEach(System.out::println);//compiles
This calls the println method of System.out for each item. Here System.out::println is the same as (String x) -> System.out.println(x).
l.stream().forEach(System.out.println(String::compareTo));//doesnt compile
You know how function calls work, right? This first calls (System.out.println(String::compareTo), then calls l.stream().forEach(result of that println call). Except println returns void so it has no result.
l.stream().forEach(String::compareTo);// doesnt compile
Here String::compareTo is the same as (String x, String y) -> x.compareTo(y) which takes two arguments. But forEach needs a lambda that takes one argument.
String comparedWith = "";
l.stream().forEach(comparedWith::compareTo);//compiles why ?
Here comparedWith::compareTo is the same as (String x) -> comparedWith.compareTo(x). This takes one argument so it's valid.

forEach will take each element of the collection and pass it to your function. So, your function has to take only one argument.
In your case, println takes one argument, thus it fits into the operation forEach accepts. When you take the instance of the String (comparedWith) and call compareTo, it takes one argument and compares the current string (empty string in your case) with your argument. There is no static methods in String that are called compareTo, so String::compareTo doesn't work.

The double colon or more accurately called "method reference" is meant to a select a method that will be called.
And when calling methods, it matters greatly to match up the numbers of provided and expected arguments.
And as you can easily deduct, those counts do no match up for your second example.

Related

How to pass parameter in Supplier function with method reference operator(::)

Sorry, it seems to be very basic in functional programming but I am not getting this idea. Actually I have a method in my code which consumes a method and another param as a parameter.
private <R> CompletableFuture<R> retryRequest(Supplier<CompletableFuture<R>> supplier, int maxRetries)
I want to call this function and pass another method(anOtherMethod) which taking one integer parameter:
CompletableFuture<Boolean> retry = this.retryRequest(this:: anOtherMethod, 2);
Not getting this how I can call this retryRequest and give anOtherMethod(123)?
I know it can work like this:
CompletableFuture<Boolean> retry = this.retryRequest(()-> anOtherMethod(123), 2);
You cannot instantiate a lambda with a specific captured value like 123 in the pure method reference variant.. You need to write the explicit lambda version with arrow, if you want to pass captured values other than the instance to execute the method on. Read more on capturing values in lambdas in this answer: Enhanced 'for' loop and lambda expressions
The only exception is an object, which itself becomes the first parameter.
Assume a signature that expects a Consumer of a String:
public void something(Consumer<String> job) {
...
The above signature will enable you to write the following calls:
String myString = " Hey Jack ";
something(myString::trim);
something(s -> s.trim());
Both do the same, and this is maybe unintuitive, because one takes an argument (the instance reference myString) and one seem not to (but it actually does, too). This works, because the compiler tries two possible resolutions for a lambda method reference (the above version with ::). On one hand, the compiler can apply signatures, as if the called method did not have any parameters, and none need passing. This is the case for myString.trim. But the compiler will also check, whether there is a static method String.trim(myString) (which luckiely there is not). If you wanted to call a static method without any parameters, then you'd have to call the class identifier with the function reference like so:
something(String::trim); // this version of trim does not exist.
This is sometimes even a problem, because if a class offers a static version of a method and an instance-related one, you get ambiguity:
public void somethingElse(Function<Integer, String> transformation) {...}
// This will not compile:
somethingElse(Integer::toString);
The above example will not compile, because the toString method exists twice, once as static Integer.toString(someInt) and once as instance related someInteger.toString().

Method reference - Difference between "Reference to a static method" and "Reference to an instance method of an arbitrary object of a particular type"

I've learned that there are 4 kinds of types in method reference. But I don't understand the difference between "Reference to a static method" and "Reference to an instance method of an arbitrary object of a particular type".
For example:
List<String> weeks = new ArrayList<>();
weeks.add("Monday");
weeks.add("Tuesday");
weeks.add("Wednesday");
weeks.add("Thursday");
weeks.add("Friday");
weeks.add("Saturday");
weeks.add("Sunday");
weeks.stream().map(String::toUpperCase).forEach(System.out::println);
The method toUpperCase is not a static method... so why can one write in the way above, rather than needing to use it this way:
weeks.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
Explanation
The method toUpperCase is not a static method... so why can one write in the way above, rather than needing to use it this way:
weeks.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
Method references are not limited to static methods. Take a look at
.map(String::toUpperCase)
it is equivalent to
.map(s -> s.toUpperCase())
Java will just call the method you have referenced on the elements in the stream. In fact, this is the whole point of references.
The official Oracle tutorial explains this in more detail.
Insights, Examples
The method Stream#map (documentation) has the following signature:
<R> Stream<R> map​(Function<? super T, ? extends R> mapper)
So it expects some Function. In your case this is a Function<String, String> which takes a String, applies some method on it and then returns a String.
Now we take a look at Function (documentation). It has the following method:
R apply​(T t)
Applies this function to the given argument.
This is exactly what you are providing with your method reference. You provide a Function<String, String> that applies the given method reference on all objects. Your apply would look like:
String apply(String t) {
return t.toUpperCase();
}
And the Lambda expression
.map(s -> s.toUpperCase())
generates the exact same Function with the same apply method.
So what you could do is
Function<String, String> toUpper1 = String::toUpperCase;
Function<String, String> toUpper2 = s -> s.toUpperCase();
System.out.println(toUpper1.apply("test"));
System.out.println(toUpper2.apply("test"));
And they will both output "TEST", they behave the same.
More details on this can be found in the Java Language Specification JLS§15.13. Especially take a look at the examples in the end of the chapter.
Another note, why does Java even know that String::toUpperCase should be interpreted as Function<String, String>? Well, in general it does not. That's why we always need to clearly specify the type:
// The left side of the statement makes it clear to the compiler
Function<String, String> toUpper1 = String::toUpperCase;
// The signature of the 'map' method makes it clear to the compiler
.map(String::toUpperCase)
Also note that we can only do such stuff with functional interfaces:
#FunctionalInterface
public interface Function<T, R> { ... }
Note on System.out::println
For some reason you are not confused by
.forEach(System.out::println);
This method is not static either.
The out is an ordinary object instance and the println is a non static method of the PrintStream (documentation) class. See System#out for the objects documentation.
Method reference quite intelligent feature in Java. So, when you use non-static method reference like String:toUpperCase Java automatically comes to know that it needs to call toUpperCase on the on the first parameter.Suppose there is two parameter a lambda expression expect then the method will call on the first parameter and the second parameter will pass as an argument of the method. Let' take an example.
List<String> empNames = Arrays.asList("Tom","Bob");
String s1 = empNames.stream().reduce("",String::concat); //line -1
String s2 = empNames.stream().reduce("",(a,b)->a.concat(b)); // line -2
System.out.println(s1);
System.out.println(s2);
So, on above example on line -1, String#concat method will call on the first parameter (that is a line-2) and a second parameter (that b for line -2) will pass as the argument.
It is possible for the multiple arguments (more than 2) method also but you need to very careful about the which sequence of the parameters.
I highly recommend you to read the Oracle's article about method references: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
That is the form of a lambda expression:
s->s.toUpperCase()
And that is a method reference:
String::toUpperCase
Semantically, the method reference is the same as the lambda expression, it just has different syntax.

why need of "println(char[] x)" when there is already "println(Object x)" - java

I was reading about println function and I came across that there is println(char[ ] x) as well as println(Object x)
https://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html#println(char[])
My question is that: As arrays in java are object so what is the need to specifically overload println() with char[] whereas rest arrays like int[] etc. uses the println(Object x) overloaded function.
println(Object x)
if you use it to print a char array (the char array is an object), it won't print the content but the objectClass#hashcode style. You can test it yourself to see the exact output.
Because they are implemented differently.
println(Object)
will (after checking for null, etc), call the parameter's toString() method and display the result of it.
The toString() method of an array is not useful: it will give you the array type and the hashcode of the array. So the overloaded form gives a more useful implementation in the case of a char[] parameter.
Note that, with most object types, the toString() method can be overridden (so overloading the println(...) method for every possible type is not necessary (or possible...). However, the toString() method cannot be overridden for arrays, so there is benefit to overloading println in this case.
Because it prints the char array as a string and otherwise prints in object form, and seeing the contents may be more convinient. You can try casting it to object first and see the difference.
Because print/ln(char[]) handles the actual printing of characters, toString() of the array object itself still provides the usual type+hash output, regardless of being an array of characters
char c[]={'a','b','c'};
Object o=c;
System.out.println(c);
System.out.println(c.toString());
System.out.println(o); // *
System.out.println(o.toString());
The * thing is interesting (and this is why I post at all, since the rest is already there in other answers) because it demonstrates that Java has single dispatch: the actual method to be invoked is decided in compilation time, based on the declared type of the argument(s). So it does not matter that o is a character array in runtime, in compilation time it seems to be an Object, and thus print/ln(Object) is going to be invoked for it.

Order of arguments while using "String..."

I was writing a method with a variable number of parameters, using the constructor proposed by Java:
public static boolean myMethod(String... strings) {
for (String s: strings) {
// Applying some logic / treatment on strings
}
}
I was wondering: how does Java behaves with the strings parameter ? Does it takes it as an ArrayList, or a simple String[] ? Is the order of the parameters kept while going through the method ?
For example, if I use my method like this:
MyMethodUtils.myMethod(first, second, third, fourth, fifth);
Am I guaranteed that first will be treated first, then second, etc ... Or not ?
Bonus question: What is the specifical name of such constructor String... (in Java) ?
Yes, ordering is preserved.
This is because String... (technically called a variable arity parameter, but often informally called "varargs") is just syntactic sugar for String[]. So:
MyMethodUtils.myMethod(first, second, third, fourth, fifth);
is identical to
MyMethodUtils.myMethod(new String[]{first, second, third, fourth, fifth});
(and in fact, you can invoke the latter).
You wouldn't expect an array's elements to change order in any other case, and nor do they with a variable arity parameter.
You can find this in JLS Sec 15.12.4.2:
If m is being invoked with k ≠ n actual argument expressions, or, if m is being invoked with k = n actual argument expressions and the type of the k'th argument expression is not assignment compatible with T[], then the argument list (e1, ..., en-1, en, ..., ek) is evaluated as if it were written as (e1, ..., en-1, new |T[]| { en, ..., ek }), where |T[]| denotes the erasure (§4.6) of T[].
Bonus question: What is the specifical name of such constructor
String... (in Java)?
Name of these type of constructors is parameterised constructor only.
The only difference is these are using Varargs.
Variable Argument (Varargs):
The varrags allows the method to accept zero or multiple arguments.
Before varargs either we use an overloaded method or take an array as the
method parameter but it was not considered good because it leads to
the maintenance problem. If we don't know how many arguments we will
have to pass in the method, var args is the better approach.
For More information
You will get these parameters in a order in which you have written , by referring your above example i can say ,
First will be first , and second will be second
As Java takes it as a string[]
Answer of bonus question
There is no specific name but the parameters you pass in such way is called as "var args"
hope you satisfied :)

Long commands in Java

I am learning to code in Java
I know what namespaces, classes and methods are
with that knowledge I understand code such as the following
CharSequence v = new BackwardString("whale");
v.toString();
However sometimes you see examples of code which are longer than this
an example being
dictionary.subSet("a","ab").size();
In the ubove example dictionary is a class and subSet() is a method.
However size() is also a method but methods cannot contain other methods, so where does size() come from and why does it work?
Another common example which i have used without giving any thought to until now is
System.out.printLn();
in this case would System be a namespace, out be a class and printLn() be a method?
dictionary.subSet("a","ab").size();
It's a chaining of method calls. dictionary.subSet("a","ab") returns a String object, on which you call the size method.
System.out.println()
System is a class (java.lang.System), out is a static variable of that class whose type is PrintStream, and println is a method of PrintStream.
dictionary.subSet("a","ab").size();
The subSet method returns a String object, you are then calling .size() on this String. It is shorthand for doing the following
String a = dictionary.subSet("a","ab")
int size = a.size();
System.out.println()
System.out returns a PrintStream method, and you are invoking the println() method of that object.
This is called Method Chanining
System.out.printLn();=
System is a class
PrintStream is a class again // ref is out
println() is a function
In this example:
dictionary.subSet("a","ab").size();
method subSet returns an object with method size which gets invoked after subSet returns.
Similar thing happens with another snippet:
System.out.printLn();
Class System contains a static field out which has a method println
This is a common practice in Java programming to pipeline method calls. Sometimes an object can return itself allowing you can call multiple methods in one line.
The . selection is done as follows:
(dictionary.subSet("a","ab")).size();
Set s = dictionary.subSet("a","ab");
s.size();
The method subSet delivers (likely) a Set,
and Set has a method size.
This is called "chaining".
To get a feeling of it:
BigDecimal n = BigDecimal.valueOf("123456780.12");
n = n.multiply(n).add(n).divide(BigDecimal.TWO).subtract(n);
BigDecimal does large numbers with precise fixed point arithmetic.
It cannot use operators, and the above is a normal style.
Selectors (that might be chained:
. member
[ index ]
( function arguments )

Categories

Resources