I have this function a:
public void a(BooleanSupplier param){}
that is called by function b:
public void b(Boolean param){
a(param)
}
The problem is that function "a" is expecting a BooleanSupplier but function b is sending a Boolean. I think I should convert a Boolean into a BooleanSupplier but I could not manage to convert one to another.
Let us take a closer look at the BooleanSupplier-interface. This is a functional interface, i.e. it has only one abstract method boolean getAsBoolean(). As we can see, the method has no parameters and returns a boolean.
Now let us look at the code presented. Method b receives one parameter Boolean param. method a receives one parameter of type BooleanSupplier. How can we convert the Boolean received by b to a BooleanSupplier? We just need to create a lambda that - when called - returns param. When written as lambda, this looks as follows:
only expression in the lambda -> return-value
^
|
() -> param;
|
v
empty parameter list
The minor type mismatch between Boolean (type of param) and boolean (expected return-type of BooleanSupplier) is resolved through autoboxing (oracle.com).
So in total, we can now call a as follows:
a(() -> param);
For further information on lambdas and their syntax, I recommend reading a tutorial on the topic, e.g. this one from oracle.com.
Related
public interface CustomerRegVali extends Function<Customer, ValidationResult>
static CustomerRegVali isEmailValid(){
return customer -> customer.getEmail().contains("#") ?
SUCCESS : EMAIL_NOT_VALID;
}
static CustomerRegVali isDobValid(){
return customer -> Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
SUCCESS : NOT_ADULT;
}
static CustomerRegVali isPhoneValid(){
return customer -> customer.getPhone().startsWith("+0") ?
SUCCESS : PHONE_NOT_VALID;
}
default CustomerRegVali and(CustomerRegVali other){
return customer -> {
ValidationResult result = CustomerRegVali.this.apply(customer);
return result.equals(SUCCESS) ? other.apply(customer) : result;
};
}
#Main method
ValidationResult result = isEmailValid()
.and(isPhoneValid())
.and(isDobValid())
.apply(customer);
Right so.. Looking back at an old uni project for functional java, I stumbled upon this combinator. Am I clueless or does .apply not get called twice on the primitives? Seems rather redundant.
You wrote
... during .and(isPhoneValid), is .this not referring to isEmailValid - and .other to isPhoneValid. With this in mind, next iteration would then be .this referring to isPhoneValid on which we will call .apply once again.
I think you're confusing this with CustomerRegVali.this, which is different. You might be imagining that you're building a structure that looks like this:
but in fact it looks like this:
Within a call to apply, this points to one of these boxes, but as you can see, there's never a case in which this points to isEmailValid while a separate other link points to isPhoneValid.
In the implementation of apply for and, you're not calling apply on this but rather on the captured value CustomerRegVali.this, which is the validator on which you invoked and.
In setting up the validator, you:
Call isEmailValid.
Invoke and on the isEmailValid validator, passing the isPhoneValid validator. This creates a new and validator that retains a reference to the isEmailValid validator and other.
Finally invoke and on the result of the first and, passing a new isDobValid validator, building a new and validator just like the previous one.
That process produces the structure in the second diagram.
So there are five validators in total, and you call apply once on each.
Please, be aware that you are building a chain of functions and the result of the chain is a function as well.
As #SilvioMayolo pointed out too, when you perform apply on the chain this function in turn will invoke, in the order you indicated, if the validation result is SUCCESS and the chain could proceed, the different, individual, CustomerRegVali apply methods.
In order to understand this behavior, consider the following interface definition.
import java.time.LocalDate;
import java.time.Period;
import java.util.function.Function;
public interface CustomerRegVali extends Function<Customer, ValidationResult> {
static CustomerRegVali isEmailValid(){
return customer -> {
System.out.println("isEmailValid called");
return customer.getEmail().contains("#") ?
SUCCESS : EMAIL_NOT_VALID;
};
}
static CustomerRegVali isDobValid(){
return customer -> {
System.out.println("isDobValid called");
return Period.between(customer.getDob(), LocalDate.now()).getYears() > 16 ?
SUCCESS : NOT_ADULT;
};
}
static CustomerRegVali isPhoneValid(){
return customer -> {
System.out.println("isPhoneValid called");
return customer.getPhone().startsWith("+0") ?
SUCCESS : PHONE_NOT_VALID;
};
}
default CustomerRegVali and(CustomerRegVali other){
return customer -> {
System.out.println("and called");
ValidationResult result = CustomerRegVali.this.apply(customer);
return result.equals(SUCCESS) ? other.apply(customer) : result;
};
}
}
And this simple test case:
public static void main(String... args) {
Customer customer = new Customer();
customer.setEmail("email#company.org");
customer.setDob(LocalDate.of(2000, Month.JANUARY, 1));
customer.setPhone("+000000000");
final CustomerRegVali chain = isEmailValid()
.and(isPhoneValid())
.and(isDobValid());
System.out.println("valid result:");
ValidationResult result = chain.apply(customer);
System.out.println(result);
customer.setPhone("+900000000");
System.out.println("\ninvalid result:");
System.out.println(chain.apply(customer));
}
This will output:
valid result:
and called
and called
isEmailValid called
isPhoneValid called
isDobValid called
SUCCESS
invalid result:
and called
and called
isEmailValid called
isPhoneValid called
PHONE_NOT_VALID
As you can see, as a consequence of the function chaining and the way you programmed these functions, the individual apply methods will be called when you invoke the final chain's apply method in the order specified and only if the chain should proceed because the validation result is SUCCESS.
Precisely, assuming your code:
#Main method
ValidationResult result = isEmailValid()
.and(isPhoneValid())
.and(isDobValid())
.apply(customer);
When you invoke apply you are invoking the second and function.
According to the implementation provided for the and function, this will in turn invoke the apply method of the function in which the second and is defined. In this case, it implies that the apply method of the first defined and function will be invoked.
In turn, again according to the implementation provided for the and function, the apply method of the function in which the first and function is defined will be invoked, which happens to be isEmailValid now.
isEmailValid is invoked. If it returns SUCCESS then, according to the logic implemented in the and function - we are moving forward now, from the first validator to the last one - it will invoke the next validator function in the chain, the one provided as argument of the first and function, isPhoneValid, in this case.
isPhoneValid is invoked. If it returns SUCCESS then, according to the logic implemented in the and function, again it will invoke the next validator function in the chain, the one passed as argument of the second and function this time, isDobValid in this case.
isDobValid is invoked. The process would continue like this if new validators exist.
Closely related, some time ago I came across this wonderful article about functional programming and partial functions. I think it can be of help.
The three isXyzValid values are of type CustomerRegVali, meaning that they're functions that take a Customer as an argument and return a ValidationResult.
The and function is a combinator that combines two validation functions into one. I.e. it returns a function that takes a customer as an argument and returns a ValidationResult according to whether the two validation functions succeed when applied to the given customer. It has a short-circuit so that if the first validation function fails then the second isn't called - the combined function simply returns the failed validation result returned by the first function.
The and combinator is defined in the example code as a non-static method of the CustomerRegValin type. It could have been defined as a standalone static method, in which case it would take two function arguments (i.e. CustomerRegVali` values) and would look like this:
CustomerRegVali and(CustomerRegVali thiz, CustomerRegVali other) {
return customer -> {
ValidationResult result = thiz.apply(customer);
return result.equals(SUCCESS) ? other.apply(customer) : result;
};
It should be clear here that apply is called for each function argument once (at most).
To use this method you would have to call it like this:
CustomerRegVali isEmailandDobValid = and(isEmailValid(), isDobValid());
If you wanted to chain another function using and, then it would look like this:
CustomerRegVali isEmailandDobAndPhoneValid = and(and(isEmailValid(), isDobValid()), isPhoneValid());
It's evidently not that readable. We could improve this if we could use and as an infix operator, e.g.:
isEmailValid() and isDobValid() and isPhoneValid()
Unfortunately Java doesn't support user-defined infix functions, however we can get fairly close by changing and to be a non-static method on CustomerRegVali - this then allows us to write the above expression like this:
isEmailValid().and(isDobValid()).and(isPhoneValid())
To do this we need to change our and definition so that it is a non-static method and also remove this first argument (as that function argument will now be the object on which we're calling the and method). As a first attempt we might think this would work:
CustomerRegVali and(CustomerRegVali other) {
return customer -> {
ValidationResult result = this.apply(customer);
return result.equals(SUCCESS) ? other.apply(customer) : result;
};
however this will fail to compile. The problem is that inside of the lambda expression (the body of the function inside the inner pair of braces), this refers to the immediate enclosing scope - the lambda itself and not to the outer CustomerRegVali object. To fix this we need to disambigute this by prefixing it with CustomerRegVali.:
CustomerRegVali and(CustomerRegVali other) {
return customer -> {
ValidationResult result = CustomerRegVali.this.apply(customer);
return result.equals(SUCCESS) ? other.apply(customer) : result;
};
This now matches the definition provided in the example. We can use this and method to chain 3 validation functions together:
CustomerRegVali isEmailandDobAndPhoneValid =
isEmailValid().and(isDobValid()).and(isPhoneValid())
and if we want to apply the function to an actual customer object then we need to call the apply method:
ValidationResult result =
isEmailValid()
.and(isDobValid())
.and(isPhoneValid())
.apply(customer);
I hope it is now clear that each validation function is only called once (at most) in this example.
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));
}
when learning Flux (reactive-core) in java, I meet following questions about Function.
This is Flux.zip() method signature:
public static <I, O> Flux<O> zip(
final Function<? super Object[], ? extends O> combinator,
Publisher<?extends I>... sources) {
return zip(combinator, Queues.XS_BUFFER_SIZE, sources);
}
And when I try to invoke this method:
Flux<User> userFluxFromStringFlux(Flux<String> usernameFlux, Flux<String> firstnameFlux, Flux<String> lastnameFlux) {
// predefined function taking object[] and returns User
Function<Object[], User> function = array -> new User(array[0].toString(),array[1].toString(), array[2].toString());
// it is working without error
Flux.zip(function, usernameFlux, firstnameFlux, lastnameFlux);
// this is also working without error
Flux.zip(array -> {
return new User(array[0].toString(),array[1].toString(), array[2].toString());
}, usernameFlux, firstnameFlux, lastnameFlux);
// but this has error with array[0] "Array type expected; found: 'org.reactivestreams.subscriber<capture<? super java.lang.object>>'"
Flux.zip(array -> new User(array[0].toString(),array[1].toString(), array[2].toString()), usernameFlux, firstnameFlux, lastnameFlux);
return null;
}
The third way which using anonymous function, but IDEA reports that there is a error :
Array type expected; found: 'org.reactivestreams.subscriber>.
I wonder why predefined Function and anonymous function with explict return is working but anonymous function?
I appreciate your help.
Not a compiler expert, but I think it has to do with the java compiler seeing an ambiguity with the short form lambda: is what you are passing an inline Publisher (since it is a functional interface) or a Function?
This confusion is made possible because the short form doesn't have an explicit return statement: in the case of the Publisher option it would mean you create a User to immediately be garbaged collected, but that's not the sort of things the compiler will forbid you to do.
So the target type of the lambda is assumed to be Publisher, and thus array is inferred to be a Subscriber. But then the array index operator is used on it, which surely must be wrong.
On the other hand, putting in the brackets { } removes that ambiguity by having an explicit return type that seem to be used in the inference. To the compiler you can no longer be representing a Publisher, so the next candidate (Function) is used.
Another way of removing the ambiguity is to show the compiler that the array is... an array:
Flux.zip((Object[] array) -> new User(array[0].toString(),array[1].toString(), array[2].toString())
, usernameFlux, firstnameFlux, lastnameFlux);
Is it true to say that in a Stream in Java 8, you can only use method references that take a single argument (if you disallow wrapping the method reference with a method call)?
I assume so because in a stream at any time you are processing a single item.
Therefore:
Something::new (must refer to a single arg constructor)
this::doSomething (must take a single arg)
Something::doSomething
(must take a single arg)
...when used in a Stream. Is this rule always true?
No, it's not. Some of the Stream methods take functional interfaces having a method with multiple arguments.
For example, Stream's sorted(Stream<T> Comparator<? super T> comparator) method, takes a Comparator, whose method has two arguments.
Here's an example of using a method reference - String::compareTo - of a method having two arguments:
System.out.println(Stream.of("a","d","c").sorted(String::compareTo).collect(Collectors.toList()));
Stream's Optional<T> max(Comparator<? super T> comparator) method is another similar example.
There are four types of methods references:
A method reference to a static method i.e.
Class::staticMethod --> (args) -> Class.staticMethod(args)
A method reference to an instance method of an object of a particular type. i.e.
ObjectType::instanceMethod --> (obj, args) -> obj.instanceMethod(args)
A method reference to an instance method of an existing object i.e.
obj::instanceMethod --> (args) -> obj.instanceMethod(args)
A method reference to a constructor i.e.
ClassName::new --> (args) -> new ClassName(args)
As you can see with the second example, a given method can take two arguments and still be translated to a method reference, this is true for the case of calling sorted , min , max etc.. of a stream.
credit to Java 8 Method Reference: How to Use it for the examples above.
Just to add to the answer from Eran, you can possibly find a real life example better to understand.
Let's assume we have a method that adds an Integer i and an intValue of a Long l to return back as a String s representation. This would look like :
String convertToStringAfterAddingValues(Long l, Integer i) {
return String.valueOf(l.intValue() + i);
}
In the world of FunctionalInterface, this could be represented as a BiFunction as an anonymous class:
BiFunction<Long, Integer, String> biFunctionAnonymous = new BiFunction<Long, Integer, String>() {
#Override
public String apply(Long l, Integer i) {
return String.valueOf(l.intValue() + i);
}
};
which in the lambda world could then be represented as:
BiFunction<Long, Integer, String> biFunctLambda = (l, i) -> String.valueOf(l.intValue() + i);
the same can be represented using method reference with the object of the class the method resides in as :
BiFunction<Long, Integer, String> biFunctMethodReference = <YourClassInstance>::convertToStringAfterAddingValues;
The following code surprisingly is compiling successfully:
Consumer<String> p = ""::equals;
This too:
p = s -> "".equals(s);
But this is fails with the error boolean cannot be converted to void as expected:
p = s -> true;
Modification of the second example with parenthesis also fails:
p = s -> ("".equals(s));
Is it a bug in Java compiler or is there a type inference rule I don't know about?
First, it's worth looking at what a Consumer<String> actually is. From the documentation:
Represents an operation that accepts a single input argument and
returns no result. Unlike most other functional interfaces, Consumer
is expected to operate via side-effects.
So it's a function that accepts a String and returns nothing.
Consumer<String> p = ""::equals;
Compiles successfully because equals can take a String (and, indeed, any Object). The result of equals is just ignored.*
p = s -> "".equals(s);
This is exactly the same, but with different syntax. The compiler knows not to add an implicit return because a Consumer should not return a value. It would add an implicit return if the lambda was a Function<String, Boolean> though.
p = s -> true;
This takes a String (s) but because true is an expression and not a statement, the result cannot be ignored in the same way. The compiler has to add an implicit return because an expression can't exist on its own. Thus, this does have a return: a boolean. Therefore it's not a Consumer.**
p = s -> ("".equals(s));
Again, this is an expression, not a statement. Ignoring lambdas for a moment, you will see the line System.out.println("Hello"); will similarly fail to compile if you wrap it in parentheses.
*From the spec:
If the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement), it is compatible with a void-producing function type; any result is simply discarded.
**From the spec (thanks, Eugene):
A lambda expression is congruent with a [void-producing] function type if ...
the lambda body is either a statement expression
(§14.8)
or a void-compatible block.
I think the other answers complicate the explanation by focusing on lambdas whereas their behavior in this case is similar to the behavior of manually implemented methods. This compiles:
new Consumer<String>() {
#Override
public void accept(final String s) {
"".equals(s);
}
}
whereas this does not:
new Consumer<String>() {
#Override
public void accept(final String s) {
true;
}
}
because "".equals(s) is a statement but true is not. A lambda expression for a functional interface returning void requires a statement so it follows the same rules as a method's body.
Note that in general lambda bodies don't follow exactly the same rules as method bodies - in particular, if a lambda whose body is an expression implements a method returning a value, it has an implicit return. So for example, x -> true would be a valid implementation of Function<Object, Boolean>, whereas true; is not a valid method body. But in this particular case functional interfaces and method bodies coincide.
s -> "".equals(s)
and
s -> true
don't rely on same function descriptors.
s -> "".equals(s) may refer either String->void or String->boolean function descriptor.
s -> true refers to only String->boolean function descriptor.
Why ?
when you write s -> "".equals(s), the body of the lambda : "".equals(s) is a statement that produces a value.
The compiler considers that the function may return either void or boolean.
So writing :
Function<String, Boolean> function = s -> "".equals(s);
Consumer<String> consumer = s -> "".equals(s);
is valid.
When you assign the lambda body to a Consumer<String> declared variable, the descriptor String->void is used.
Of course, this code doesn't make much sense (you check the equality and you don't use the result) but the compiler doesn't care.
It is the same thing when you write a statement : myObject.getMyProperty() where getMyProperty() returns a boolean value but that you don't store the result of it.
when you write s -> true, the body of the lambda : true is a single expression .
The compiler considers that the function returns necessarily boolean.
So only the descriptor String->boolean may be used.
Now, come back to your code that doesn't compile.
What are you trying to do ?
Consumer<String> p = s -> true;
You cannot. You want to assign to a variable that uses the function descriptor Consumer<String> a lambda body with the String->void function descriptor.
It doesn't match !