I have a working Java app that I am looking to update to use more of Java 8's features.
I have a Function as follows:
protected static Function<Notification,Notification>
coverpageNotification = n -> n
.withMessage("COVERPAGE MESSAGE")
.withDate(new Date());
and I call it now using:
s = new HashSet<Notification>();
checkNotificationStatus(true, coverpageNotification.apply(new Notification()), s);
...
...
Instead of saying coverpageNotification.apply(new Notification()), is there a more expressive way of doing this using lambdas?
There is no more expressive syntax to call Function.apply()
Apart from that, what are you trying to achieve with lambdas?
In its current form, this does not have any advantage over a simple method:
static Notifaction addCoverPage(Notifaction n){
return n.withMessage("COVERPAGE MESSAGE")
.withDate(new Date());
}
and
checkNotificationStatus(true, addCoverPage(new Notification()), s);
If you still need a function at some point, you can also turn the method into one:
Function<Notification,Notification> x = SomeClass::addCoverPage;
Related
tl;dr:
How do/can I store the function-handles of multiple js-functions in java for using them later? Currently I have two ideas:
Create multipe ScriptEngine instances, each containing one loaded function. Store them in a map by column, multiple entries per column in a list. Looks like a big overhead depending on how 'heavy' a ScriptEngine instance is...
Some Javascript solution to append methods of the same target field to an array. Dont know yet how to access that from the java-side, but also dont like it. Would like to keep the script files as stupid as possible.
var test1 = test1 || [];
test1.push(function(input) { return ""; });
???
Ideas or suggestions?
Tell me more:
I have a project where I have a directory containing script files (javascript, expecting more than hundred files, will grow in future). Those script files are named like: test1;toupper.js, test1;trim.js and test2;capitalize.js. The name before the semicolon is the column/field that the script will be process and the part after the semicolon is a human readable description what the file does (simplified example). So in this example there are two scripts that will be assigned to the "test1" column and one script to the "test2" column. The js-function template basically looks like:
function process(input) { return ""; };
My idea is, to load (and evaluate/compile) all script files at server-startup and then use the loaded functions by column when they are needed. So far, so good.
I can load/evaluate a single function with the following code. Example uses GraalVM, but should be reproducable with other languages too.
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
final Invocable invocable = (Invocable) engine;
engine.eval("function process(arg) { return arg.toUpperCase(); };");
var rr0 = invocable.invokeFunction("process", "abc123xyz"); // rr0 = ABC123XYZ
But when I load/evaluate the next function with the same name, the previous one will be overwritten - logically, since its the same function name.
engine.eval("function process(arg) { return arg + 'test'; };");
var rr1 = invocable.invokeFunction("process", "abc123xyz"); // rr1 = abc123xyztest
This is how I would do it.
The recommended way to use Graal.js is via the polyglot API: https://www.graalvm.org/reference-manual/embed-languages/
Not the same probably would work with the ScriptEngine API, but here's the example using the polyglot API.
Wrap the function definition in ()
return the functions to Java
Not pictured, but you probably build a map from the column name to a list of functions to invoke on it.
Call the functions on the data.
import org.graalvm.polyglot.*;
import org.graalvm.polyglot.proxy.*;
public class HelloPolyglot {
public static void main(String[] args) {
System.out.println("Hello Java!");
try (Context context = Context.create()) {
Value toUpperCase = context.eval("js", "(function process(arg) { return arg.toUpperCase(); })");
Value concatTest = context.eval("js", "(function process(arg) { return arg + 'test'; })");
String text = "HelloWorld";
text = toUpperCase.execute(text).asString();
text = concatTest.execute(text).asString();
System.out.println(text);
}
}
}
Now, Value.execute() returns a Value, which I for simplicity coerce to a Java String with asString(), but you don't have to do that and you can operate on Value (here's the API for Value: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html).
Is it able to write this code embedded into Optional method chain:
Optional<Application> appOpt = this.applicationDao.findById(application.getCode());
Application app = appOpt.orElse(Application::new);
if (!appOpt.isPresent()) {
app.get().setUserCreation("user");
app.get().setTimestampCreation(new Date());
}
I'd like to avoud using again the previous appOpt object. I would like to embed all this logic inside an Optional method chain.
I guess there should be another more elegant way to get it.
I've tried to play with ifPresent but it returns void and so I'm not able to chain orElse method:
appOpt.ifPresent(a -> {
a.setUserCreation("userCreation"));
app.setTimestampCreation(new Date());
})
.orElse(Application::new);
I hope I've explained so well.
Any ideas?
After looking again at your original code, it looks like the logic should run if the Optional is empty:
Application application = appOpt.orElseGet(() -> {
Application app = new Application();
app.setUserCreation("userCreation"));
app.setTimestampCreation(new Date());
return app;
});
I'm trying to refactoring some for-loops into lambda expressions, most of them are working fine, but I'm struggling with for-loops that contains two if-statements.
Code
for (B2KTransactionDTO b2kTransactionDTO : result) {
//Generate loyaltyMatchId based on transaction input
String loyaltyMatchId = getLoyaltyMatchIdBasedOnTransactionDTO(b2kTransactionDTO);
if (loyaltyMatchIdAmountMap.containsKey(loyaltyMatchId)) {
BigDecimal cashback = loyaltyMatchIdAmountMap.get(loyaltyMatchId);
b2kTransactionDTO.addLoyaltyPoints(cashback);
}
String loyaltyMatchInsuranceId = getLoyaltyMatchInsuranceIdBasedOnTransactionDTO(b2kTransactionDTO);
if (loyaltyMatchInsuranceIdAmountMap.containsKey(loyaltyMatchInsuranceId)) {
BigDecimal cashback = loyaltyMatchInsuranceIdAmountMap.get(loyaltyMatchInsuranceId);
b2kTransactionDTO.addLoyaltyPoints(cashback);
}
}
I refactored this to the following code:
result.forEach(b2kTransactionDTO -> {
//Generate loyaltyMatchId based on transaction input
String loyaltyMatchId = getLoyaltyMatchIdBasedOnTransactionDTO(b2kTransactionDTO);
if (loyaltyMatchIdAmountMap.containsKey(loyaltyMatchId)) {
BigDecimal cashback = loyaltyMatchIdAmountMap.get(loyaltyMatchId);
b2kTransactionDTO.addLoyaltyPoints(cashback);
}
String loyaltyMatchInsuranceId = getLoyaltyMatchInsuranceIdBasedOnTransactionDTO(b2kTransactionDTO);
if (loyaltyMatchInsuranceIdAmountMap.containsKey(loyaltyMatchInsuranceId)) {
BigDecimal cashback = loyaltyMatchInsuranceIdAmountMap.get(loyaltyMatchInsuranceId);
b2kTransactionDTO.addLoyaltyPoints(cashback);
}
});
Is it possible to even futher lambda-nize this?
Thanks
This is not the answer you are looking for.
I would say, don't use lambda's here.
Lambda's can help you to utilise parralelism features of cpu's to speed up processing of large datasets.
In my experience it's not worth the hassle of utilising a lambda with smaller datasets(<10(0).000);
Keep your code readable and maintainable and pluggable.
Learn to make objects that handle purposes. Don't put all the things in one object and end up with veryLongVariableNamesThatDescribeAPurpose.
When long variable names occur it should be a signal to you that you can refactor that code into several objects that handle a single purpose.
If you really want to use lambda's try the following:
Seperate objects for value holders and processors and methods for seperate tasks, it will be easier in to utilise lambda's when needed because you can simply plug in the methods for the tasks required and pass on the value holder objects to get your desired results.
So, not the answer you're looking for, but this was too long really to explain in a comment.
I think you also should consider refactor your code because it looks like there's a lot of duplication between the match and matchInsurance stuff.
private static void addLoyaltyPoints(Collection<B2KTransactionDTO> result, Map<String, BigDecimal> ids, Function<B2KTransactionDTO, String> extractId)
{
result.stream()
.filter(b -> ids.containsKey(extractId.apply(b)))
.forEach(b -> b.addLoyaltyPoints(ids.get(extractId.apply(b))));
}
Then the whole code you posted could become:
addLoyaltyPoints(result, loyaltyMatchIdAmountMap, Use::getLoyaltyMatchIdBasedOnTransactionDTO);
addLoyaltyPoints(result, loyaltyMatchInsuranceIdAmountMap, Use::getLoyaltyMatchInsuranceIdBasedOnTransactionDTO);
Edit: another version of addLoyaltyPoints (more concise, less expressive):
private static void addLoyaltyPoints(Collection<B2KTransactionDTO> result, Map<String, BigDecimal> ids, Function<B2KTransactionDTO, String> extractId)
{
result.stream()
.forEach(b -> b.addLoyaltyPoints(ids.getOrDefault(extractId.apply(b), new BigDecimal(0))));
}
I have method and need to test it:
void update() {
_cleaner.clear();
_updator.upadate();
}
The ordering of calls is important for this scenario. I want to write test like this:
void updateTest(){
Integer CLEAR = 0, UPDATE = 1;
Stack<Integer> callStack = new Stack<>();
Cleaner cleaner = mock(Cleaner.class);
Updator updator = mock(Updator.class);
when(cleaner.clear()).callback(() -> callStack.add(CLEAR));
when(updator.update()).callback(() -> callStack.add(UPDATE));
Some testingObj = new Some(cleaner, updator);
testingObj.update();
assertEquels(CLEAR, callStack.pop());
assertEquels(UPDATE, callStack.pop());
assertTrue(callStack.isEmpty());
}
_cleaner.clear() and _updator.upadate() returns void. It is clear that
when(cleaner.clear()).callback(() -> callStack.add(ClearCall));
when(updator.update()).callback(() -> callStack.add(UpdateCall));
is invalid code. What can I write except those lines for success? How to setup callback for method (with void as type of result) call by mockito?
I recommend you use the InOrder verifier to confirm that the methods are called in the order you want. See here for some of the documentation: http://site.mockito.org/mockito/docs/current/org/mockito/InOrder.html
This example is based on code straight from that documentation:
InOrder inOrder = inOrder(cleaner, updator);
inOrder.verify(cleaner).clear();
inOrder.verify(updator).update();
How might a Java program wrap a value into a scala.Either? For example, how would the following Scala code be written in Java?
Right("asdf")
Left(new Exception())
The following fails with "cannot find symbol method apply(java.lang.String)"
Right.apply("asdf");
The following fails with "cannot find symbol method apply(java.lang.Exception)"
Left.apply(new Exception());
If I understand the question correctly, assume you have the following Scala method:
def foo(stringOrDate: Either[String, Date]) {
//...
}
you can call it from Java code by single creating Either subclasses instances:
scalaObject.foo(new Left<String, Date>("abc"));
scalaObject.foo(new Right<String, Date>(new Date()));
If you want to pass functions from Java code, you have to implement Function* trait depending on the function arity:
def foo(stringOrStringFun: Either[String, () => String]) {
//...
}
In Java:
scalaObject.foo(new Left<String, scala.Function0<String>>("abc"));
scalaObject.foo(new Right<String, scala.Function0<String>>(
new scala.Function0<String>() {
#Override
public String apply() {
throw new RuntimeException();
}
}));
Of course in Scala it is much simpler as it supports lambdas on the syntax level:
foo(Left("abc"))
foo(Right(throw new RuntimeException()))