I am still learning lambdas in java. I have a lambda function like this.
static MyClass myFunc(ClassB user) {
return (info, cn) -> info.user.equals(user);
}
Now this is being called/used like this:
protected final MyClass myClassObject = MyClass.myFunc(userObject);
Where MyClass is an interface
I have two doubts here:
Since the lambda function requires info as well, where am I passing info object to it? I am definitely using it but not passing it anywhere. So, how is it using info
I want to print the value of info object inside lambda function using System.println. How can I do that?
Related
I am a newbie in java functional interfaces so I want to see if this is possible and if not please explain me why not and what is possible in order to achieve my idea
I have these classes
public class A {
...
public String getInfo();
...
}
public class B {
...
public String getOtherInfo();
...
}
I want to pass the references to these functions to another object like this:
obj.init(A::getInfo)
obj.init(B::getOtherInfo)
so that later I can use/call these functions on different objects of type A or B inside the build functions:
obj.build(a1);
obj.build(a2);
...
obj.build(b1);
obj.build(b2);
PS1 I cannot use regular interfaces for this cause there are lot of getters and lots of classes similar to A which I want to use for this procedure and they are not related with one another
PS2 I try to avoid reflection cause you cannot trace the function calls
PS3 my example is not exactly working as is it throws this error: "non static method cannot be referenced from a static context"
A::get is a Java Method Reference. You should be able to store it for use later. As it's an instance method you'll need the instance object as well. So something like this might work:
Function<A,String> getFunction = A::get;
And whenever you need to use it you can do
//assuming you have an object instance of A which is a
getFunction.apply(a)
You can also pass it to other methods by declaring the method to take a functional parameter like this:
public void someOtherMethod(Function<A,String> param) {
//do whatever with param.
//invoke this with an instance of A when you're ready
param.apply(a);
}
Here's a reference that might help: https://www.baeldung.com/java-8-double-colon-operator
Made 2 mistakes
should have used Function<T, R> instead of Supplier
the error is thrown even if there is a slight mismatch of parameters even on the generic types. So an example of my function which accepts the Function parameter should be declared like this:
public <T extends Base> init (Function <T, String> f){
this.f = f;
}
and later I do something like:
public String build (A a){
return this.f.apply(a);
}
(so I had to make A, B implement some useless interface)
This question already has answers here:
Lazy evaluation for logging in Java 8
(6 answers)
Closed 2 years ago.
I have a debug log statement in my code to which I am passing a result of costly method call.
log.debug("Data - {}", obj.costlyMethodCall());
Now, even if debug logging is disabled, obj.costlyMethodCall() will always be evaluated to be passed as method argument.
One way to mitigate this is to have a explicit check if debug logging is enabled
if (log.isDebugEnabled()) {
log.debug("Data - {}", obj.costlyMethodCall());
}
But this reduces code readability.
Is there any better way to make invocation of obj.costlyMethodCall() lazy or conditional here?
Usually this is solved by having a method accepting something similar to a Supplier instead of a concrete Object so that you can pass in something like
log.debug("Data - {}", () -> obj.costlyMethodCall());
where log.debug is something like
public void debug(String message, Supplier<Object> supplier) {
Object value = supplier.get(); // costlyMethodCall is only called here
// ...
}
If you are already extensively bought into a logging framework, defining your own methods, as suggested by Smutje, may not be a practical option.
Instead, define a static method something like:
static <T> Supplier<T> lazy(Supplier<? extends T> delegate) {
return new Supplier<T>() {
#Override public T get() { return delegate.get(); }
#Override public String toString() { return Objects.toString(get()); }
};
}
Then provide this as an argument to your call:
log.debug("Data - {}", lazy(() -> obj.costlyMethodCall()));
If you don't provide a Supplier which overrides toString(), the logging library can't (necessarily) know that it needs to evaluate the supplier to build the toString(). Ideone example.
Yes, you could use lamdba expression to delay that. New versions of logger use this approach, like log4j 2.4. You don't need to provide new methods, just use newer logging API if you can.
You can do the following:
log.debug("Data - {}", () -> obj.costlyMethodCall());
They added this in recent logger where you need to delay String usage, without polluting your code with the if(log.isDebugEnabled())...
You pass a Supplier that will return the Strings, only once called.
You can check this link if you need to: https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/
I have a library written in kotlin which i want to use in my Java program, but i don't know how to call an asynchronous method correctly.
/*This is my asynchronous kotlin method from the library*/
fun getNames(callback: (List<String>) -> Unit) = ...
/*In Java i want to call this method*/
List<String> names = getNames(...);
What parameter do i have to pass into the function in Java?
IntelliJ says i need something like this: 'kotlin.jvm.functions.Function1<? super java.util.List<String>,kotlin.Unit>' But i don't know how to instantiate such a class.
Ok, first of all give it a look at this great response from Kirill Rakhman.
Now, the result given by a callback from a asynchronous operation will come from the parameter. In this case it'll be the (List<String>) at the fun getNames().
A simple usage of this function in JAVA (8+) can look like this :
getNames(
strings -> {
strings.forEach(System.out::println);
return Unit.INSTANCE;
}
);
I have a class that, in essence, looks like this:
class Checkpointer {
public <Input,Output> Output runFunction(Input input, Function<Input,Output> function) {
Output output;
// Sometimes run the function, sometimes return an Output from a cache
return output
}
}
I would like to mock this class using Mockito doAnswer:
Checkpointer checkpointer; // mocked via #Mock annotation
Mockito
.doAnswer(/* ??? */)
.when(checkpointer)
.runFunction(Mockito.any(), Mockito.any());
The function I want to mock needs to be generic. Can this be done?
For example, my first attempt produced the following. Not only did I resort to Object as the type arguments for Function, but the compiler was still unhappy with unchecked casting:
Mockito.doAnswer((invocation) ->
{
// compiler is not happy with this cast V
Function<Object,Object> function = (Function<Object,Object>)invocation.getArguments()[1];
return function.apply(invocation.getArgument(0));
}).when(checkpointer).runFunction(Mockito.any(), Mockito.any());
If this can't be done, I think can try writing my own mock class extending the first and use Mockito.spy.
The problem here is that you insist on using getArguments, which returns an Object[]
Since you know the index of the Function argument, you can use getArgument(index), as you're doing the line after that.
final Function<String, String> argument = invocation.getArgument(1);
Is this what you're looking for? Type inference for the getArgument generic type is working fine.
If not, can you provide a more elaborate example?
I am trying to understand the ifPresent() method of the Optional API in Java 8.
I have simple logic:
Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));
But this results in a compilation error:
ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)
Of course I can do something like this:
if(user.isPresent())
{
doSomethingWithUser(user.get());
}
But this is exactly like a cluttered null check.
If I change the code into this:
user.ifPresent(new Consumer<User>() {
#Override public void accept(User user) {
doSomethingWithUser(user.get());
}
});
The code is getting dirtier, which makes me think of going back to the old null check.
Any ideas?
Optional<User>.ifPresent() takes a Consumer<? super User> as argument. You're passing it an expression whose type is void. So that doesn't compile.
A Consumer is intended to be implemented as a lambda expression:
Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));
Or even simpler, using a method reference:
Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);
This is basically the same thing as
Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
#Override
public void accept(User theUser) {
doSomethingWithUser(theUser);
}
});
The idea is that the doSomethingWithUser() method call will only be executed if the user is present. Your code executes the method call directly, and tries to pass its void result to ifPresent().
In addition to #JBNizet's answer, my general use case for ifPresent is to combine .isPresent() and .get():
Old way:
Optional opt = getIntOptional();
if(opt.isPresent()) {
Integer value = opt.get();
// do something with value
}
New way:
Optional opt = getIntOptional();
opt.ifPresent(value -> {
// do something with value
})
This, to me, is more intuitive.
Why write complicated code when you could make it simple?
Indeed, if you are absolutely going to use the Optional class, the most simple code is what you have already written ...
if (user.isPresent())
{
doSomethingWithUser(user.get());
}
This code has the advantages of being
readable
easy to debug (breakpoint)
not tricky
Just because Oracle has added the Optional class in Java 8 doesn't mean that this class must be used in all situation.
You can use method reference like this:
user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);
Method ifPresent() get Consumer object as a paremeter and (from JavaDoc): "If a value is present, invoke the specified consumer with the value." Value it is your variable user.
Or if this method doSomethingWithUser is in the User class and it is not static, you can use method reference like this:
user.ifPresent(this::doSomethingWithUser);
Use flatMap. If a value is present, flatMap returns a sequential Stream containing only that value, otherwise returns an empty Stream. So there is no need to use ifPresent() . Example:
list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());