Java java.util.function.Consumer when argument needs to be transformed - java

I would like to create a lambda replacement for this current code:
Map<String,Consumer> executionMap = new HashMap<>();
executionMap.put("operation1", str -> this.getEntity().setBooleanCondition(Boolean.parseBoolean(str))
For cases where I don't need to do transform the argument I have this:
executionMap.put("operation2", this.getEntity()::setAStringValue);
I am annoyed because I can figure out how to make the boolean case as elegant.
Additional example of being annoyed:
executionMap.put("operation3", str -> {
this.getEntity().setAStringValueA(str);
this.getEntity().setAStringValueB(str);
});
For this second case I tried :
executionMap.put("operation3",
this.getEntity()::setAStringValueA.andThen(this.getEntity()::setAStringValueB);
But this got a compilation error.
I feel like the answer(s) are obvious but I am not seeing the path.

Your operation3 is pretty straightforward.
executionMap
.put("operation3", ((Consumer<String>)this.getEntity()::setAStringValueA)
.andThen(this.getEntity()::setAStringValueB));

Related

How to pattern match a tuple of Option with defined type in Java with Vavr

new Vavr user here.
I am trying to pattern match a tuple of options to execute a statements if both of them are Some, in Scala I would have done this with:
val maybeThis: Option[String] = ???
val maybeThat: Option[String] = ???
(maybeThis, maybeThat) match {
case (Some(dis), Some(that)) => ???
case _ => ???
}
In Java, I am trying this approach:
Tuple2<Option<String>, Option<String>> tuple = new Tuple2<>(Option.of(...), Option.of(...));
return Match(tuple).of(
Case($Tuple2($Some($(instanceOf(String.class))), $Some($(instanceOf(String.class)))),
(someThis, someThat) -> methodWhichEatsTwoStrings(someThis.get(), someThat.get())),
Case($(), t -> run(() -> {
throw new NullPointerException(...);
})));
However, with this implementation the compiler complains that it was expecting Some<Object> instead of Some<String>, same error happens if I omit the $(instanceOf(String.class) in the pattern.
I am moderately sure this is merely a problem of proper syntax, yet I am struggling to find the correct documentation.
Where am I wrong?
Thanks
There's a vavr API construct called for comprehension that tries to mimic Scala's for comprehensions to the extent that it's possible to do in Java. With that construct you could solve your problem quite elegantly. See the For overload for handling two Options for more details. Here's an example code snippet:
String methodWhichEatsTwoStrings(String v1, String v2) {
return v1 + v2; //combine the two values in some way
}
...
Option<String> option1 = Option.some("value1");
Option<String> option2 = Option.some("value2");
String combined = For(option1, option2)
.yield((v1, v2) -> methodWhichEatsTwoStrings(v1, v2))
.getOrElseThrow(() -> new NullPointerException("reasons"));
Of course, you could use Option wrapping values of different types for option1 and option2, or combine multiple options, not just two. You could also use a different type for the return value of the yield function as well. I used String everywhere for the sake of simplicity and to conform to your original example.
I would like to add that I would try to avoid throwing NullPointerException in case one or both of the options are empty. Maybe try to use another vavr data type like Either to represent such an error case?

Is it good idea to use Optional.orElseGet to do some logging logic

I want to use Optional for handling null values, the "tricky" part which I cannot think of what is the best way to do - is that I want to do logging if value is null. I can achieve that with following code - but it feels awkward.
(Update: I have posted my own answer, with Optional from Java 9)
Lets say code looks like this:
// logLine.getSomeProperty returns Optional<String>
List<LogDetails> logDetails = logLine.getSomeProperty()
.map(this::extractLogDetails)
.orElseGet(() -> logError(logLine));
List<LogDetails> extractLogDetails(String s) {
List<LogDetails> logDetails = new ArrayList<>();
String sp = "(?:([A-Z0-9]{5,7})-([A-Z0-9]{9})-(.{4}))";
Pattern p = Pattern.compile(sp, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(s);
while (m.find()) {
logDetails.add(new LogDetails(m.group(1), m.group(2), m.group(3)));
}
return logDetails;
}
List<LogDetails> logError(LogLine logLine) {
log.error("Error while ... {} ", logLine));
persistence.setErrorStatus(logLine, FAILED_PARSING);
return new ArrayList<>();
}
It would do what I want, but I have several "problems" with it.
I found it odd, that method called orElseGet is used for logging
errors.
I could replace orElseGet with orElseThrow and logError there and DO NOT throw anything - which I don't like either.
logError method returns List which I don't use and it looks weird to return something from method which should be void.
Simply there must be better way
Cases where someProperty is not null, but there are no matches - I would like to log as well, but for that I would need another line of code to check if logDetails.size() == 0
The orElseGet is not really intended as an error handling mechanism, but as a way to generate a different default value in case the Optional instance is not carrying any.
If you want to check if the Optional is empty explicitly, simply use the Optional.isPresent() check, and do the logError() in that case.
What you need to think first is, if the Optional is empty, what do you want to do? Apart from logging the error, do you want to proceed with an empty list?
If yes then you could have something like this:
List<LogDetails> logDetails = logLine.getSomeProperty()
.map(this::extractLogDetails)
.orElseGet(Collections::emptyList);
After which you could do:
if (logDetails.isEmpty()) {
logError(logline);
}
Alternatively, if you do not want to have an empty list at all, you could keep things at optional level. This way, both cases where the getSomeProperty() is empty or when the generated list is empty are handled in the same way.
Optional<List<LogDetails>> logDetailsOpt = logLine.getSomeProperty()
.map(this::extractLogDetails)
.filter(list -> !list.isEmpty());
if (!logDetailsOpt.isPresent()) {
logError(logLine);
}
In both cases, logError() is not expected to return anything. It is doing what it is intended to do in its name, logging the error.
Rather than trying to overuse the functionality of Optional, try to make your intentions in your code clear. There is more value in readability.
Rather than changing result type or logging inside stream you can simply return partitioned Map. Then after obtaining the result, execute log function on the resulting map accordingly.
Map<Boolean, List<String>> map = Stream.of("a", "aaa", "aaaa")
----
.collect(() -> Collectors.partitioningBy(predicate))
----
While I am grateful for the answers, but I just recently find out, that Java 9 introduced new method to Optional and I like it best.
Here is example.
Optional.ofNullable(user).ifPresentOrElse( u -> logger.info("User is:" + u.getEmail()),
() -> logger.info("User not found"));

How to add type constraints to parameterSpec for method

I'm trying to do exactly what the title says -- I'd like to generate a method spec that looks something like:
public void doSomethingWithThis( Container<? extends ImportantInterface> argument ) {
//1. Collect UnderPants
//2. ...
//3. Profit
}
I understand I can just use the raw type, but generated thing will be consumed by others down stream, and having the type info pop up in their IDEs ( and mine for that matter :/ ) would make my bug solving life easier down the line...
So, I'm a toolbox and 7 more minutes digging around found the path to the answer. The question in the comment points in the right direction, though it's using ParameterizedTypeName.create() which is now ParameterizedTypeName.get()
Code for sample purposes because someone else might find this useful.
ClassName containerClassName = ClassName.get(Container.class);
TypeName wildcardTypeName = WildcardTypeName.subtypeOf(ImportantInterface.class);
ParameterizedTypeName parameterTypeName = ParameterizedTypeName.get(containerClassName, wildcardTypeName);
classBuilder.addMethod(MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterTypeName, "cargo")
.addStatement(CodeBlock.builder()
.addStatement("//1. Collect Underpants")
.addStatement("//2. ...")
.addStatement("//3. Profit!!!")
.build())

Java 8 lambda expression is present

First I need to check if data is present in list then get else set default or empty value on a Java 8 stream.
Currently I am using below code without isPresent but I dont know how to use isPresent in java8.
I am trying something below which is not perfect:
String isScheme = (this.mapProgramApproaches.stream().findFirst().isPresent())? this.mapProgramApproaches.stream().findFirst().get().getIsScheme().toString() : "0";
Where as mapProgramApproaches this is set.
Don't use isPresent() (it makes no sense to run the Stream pipeline twice).
You can use map to map the value of the Optional to the required String, and then
use orElse() to return a default value when the Optional value is not present:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(o->o.getIsScheme().toString())
.orElse("0");
Maybe you are looking for something like this:
String isScheme = this.mapProgramApproaches.stream()
.findFirst()
.map(p -> p.getIsScheme().toString())
.orElse("0");
I'm not sure about context in which you are doing this, but I suppose that you would like to check whether some object is scheme and then do something with that. In that case I would suggest implement it like this:
List<String> mapProgramApproaches = new ArrayList<>();
mapProgramApproaches.stream()
.filter(this::isScheme)
.findFirst()
.ifPresent(this::doYourCode)
.orElse(defaultValue);
It will make your code cleaner. And will help to avoid additional conditionals!

Play framework: is there a way to avoid strange form helper syntax?

I am trying to build a form with Play Framework 2, the usual syntax is:
#helper.form(action = routes.Application.submit, 'id -> "myForm") {
}
Note that the single quotation mark is before id is opened and never closed.
Is there another syntax that I can use to do the same thing?
The 'id is a Symbol.
You could use the Symbol("sym") syntax if you don't like this one, but it is not standard.
scala> 'symbol == Symbol("symbol")
res0: Boolean = true
You could work around it with an implicit conversion. This will require using a scala source file, though (seems like you're using java, but you can mix them).
app/libs/SymbolImplicits.scala
package example.libs
object SymbolImplicits {
implicit def string2Symbol[A](s: (String, A)): (Symbol, A) = (Symbol(s._1), s._2)
}
Then in your view you would #import example.libs.SymbolImplicits._, so you can then do:
#helper.form(action = routes.Application.submit, "id" -> "myForm") {
}
"id" -> "myForm" is then implicitly converted to 'id -> "myForm".
To avoid using that import in every view, you could also add this line to build.sbt (or in Build.scala project properties) instead:
TwirlKeys.templateImports += "example.libs.SymbolImplicits._"
No, that's required syntax for Scala's Symbol as pointed in other answer, anyway except that it looks weird for it's perfectly valid and there's no reason to fight with it.

Categories

Resources