I have the following problem. Let's say you have 2 Optional variables
Optional<Contact> c1 = ...
Optional<Contact> c2 = ...
and a method which needs 2 variables of type Contact
void match(Contact c1, Contact c2) {...}
and you need to unwrap both c1 and c2 Optional vars and pass them into the match() method.
My question is "Which is the most elegant way to do that in Java 8?"
So far I've found 2 ways:
by using isPresent
if (c1.isPresent() && c2.isPresent()) {
match(c1.get(), c2.get());
}
by using nested ifPresent
c1.ifPresent((Contact _c1) -> {
c2.ifPresent((Contact _c2) -> {
match(_c1, _c2);
});
});
Both ways are terrible in my opinion. In Scala I can do this:
for {
contact1 <- c1
contact2 <- c2
} yield {
match(contact1, contact2);
}
is there a way in Java 8 to do it neater than I outlined above?
Solution you provided in scala is just syntax sugar for using flatMaps internally. You can use flatmaps in Java 8 too (but there are no syntax sugar for it).
c1.flatMap(contact1 -> c2.flatMap(contact2 -> match(contact1, contact2)));
it is almost the same thing as solution 2 you provided. You also can use applicative functor from https://github.com/aol/cyclops-react (I'm one of contributors) or any other functional java 8 library.
Applicative functor
Optional<String> o3 = Maybe.fromOptional(o1).ap2(String::concat).ap(o2).toOptional();
For-comprehension
Do.add(o1)
.add(o2)
.yield(a->b->a.concat(b));
You could desugar the Scala for-comprehension to map/flatMap in Java 8 with a function like:
public static <T,K,V> Optional<V> map2(Optional<T> opt1, Optional<K> opt2, BiFunction<T, K, V> f) {
Optional<V> result = opt1.flatMap(t1 -> opt2.map(t2 -> f.apply(t1, t2)));
return result;
}
And then pass your function match
If you consider the arguments not having values as an exception then you could handle them like:
try {
match(c1.orElseThrow(NoVal::new), c2.orElseThrow(NoVal::new));
} catch (NoVal ex) {
...
}
If they aren't an exceptional case then I would go with your first option as being more explicit about your intent. In my view it's pretty clear and readable, and easy to change to use orElse if you wish to switch to using defaults if the optionals are empty.
Related
I have a list and I want to find out if it contains any other elements than what I have in the enum.
I have this working:
boolean containsMyEnumCode(List<String> processCodes) {
if (null != processCodes) {
for (final String process : processCodes) {
if (!(Arrays.stream(MyEnumCode.values()).anyMatch((p) -> p.name().equals(process)))) {
return true;
}
}
}
return false;
}
This works, but how could I replace for loops with a stream, and have it in fewer lines?
Instead of null check, you can use Stream.ofNullable() (available from Java 9 onwards) which will create a stream with a single element (list of processors) or empty stream. Apply flatMap() to turn it to a stream of strings. And then apply anyMatch() as a terminal operation which will determine whether at least one process in the stream matches with the given predicate.
Note: that condition !Arrays.stream().anyMatch() means that none of elements in the stream should match the predicate passed to the anyMatch(). And that is the meaning of the operation noneMath(). A change of the terminal operation will make the condition more readable by eliminating the need in logical not in front of it Arrays.stream().noneMath().
Another improvement that is made to this code was inspired by suggestions from Holger and k314159.
Stream of enum constants Arrays.stream(MyEnumCode.values())... from the original code that is used in the condition discussed above has a performance overhead. Method values() creates an array of enum constants at every call. And it will be invoked for every element in the list. Therefore it makes sense to introduce a local variable that will store a Set of enum-names and check every element in the stream against this set.
Also as Holger pointed out null-friendly solution will disguise the problem. anyMatch() will return false in case of an empty stream and this result will be accepted as valid instead of raising NPE, and then this list can be stored somewhere and will cause problems in the future.
Since I'm providing two solutions here I've implemented one in such a way that it will raise an exception with a custom message, and another as being null-friendly by using Stream.ofNullable().
public static boolean containsNonEnumCode(List<String> processCodes) {
Set<String> names = getEnumNames(MyEnumCode.class);
return Stream.ofNullable(processCodes)
.flatMap(List::stream)
.anyMatch(process -> !names.contains(process));
}
Solution for Java 8 (requested by PO in the comment) implemented as null-hostile by using Objects.requireNonNull().
public static boolean containsNonEnumCode(List<String> processCodes) {
Set<String> names = getEnumNames(MyEnumCode.class);
return Objects.requireNonNull(processCodes, "processCodes list in null")
.stream()
.anyMatch(process -> !names.contains(process));
}
The method below expects the Class of an enum as a parameter and generates a Set of enum names.
public static <T extends Enum<T>> Set<String> getEnumNames(Class<T> enumClass) {
return EnumSet.allOf(enumClass).stream()
.map(T::name)
.collect(Collectors.toSet());
}
Starting with Optional.ofNullable on the collection passed through as a parameter you could do something like this:
Optional.ofNullable(processCodes).stream()
.flatMap(Collection::stream)
.anyMatch(code -> Arrays.stream(MyEnumCode.values()).anyMatch(v -> v.name().equals(code)));
I'm primarily a JavaScript developer, but am currently working on some Groovy code and haven't been able to figure out how to do something that's super-simple in JavaScript.
The JavaScript equivalent of what I'm trying to do follows.
I'm specifically trying to figure out the Java (or Groovy) equivalent of creating an object in JS (map in Java) out of just the existing variable names, e.g. {a, b, c} shorthand in the code snippet below. Any guidance will be much appreciated!
javaScriptExample()
function javaScriptExample () {
// the variables already exist in the program that I'm working in
const a = 'a'
const b = 'bee'
const c = 'see'
// ➡️ Here's where I'm stuck. ⬅️
// I simply want to be able to arbitrarily pass variable keys and values
// as a map to another function, _using just the variable keys_,
// e.g. the equivalent of JavaScript's `{a, b, c}` in the next call
doOtherStuffWithVariables({a, b, c})
}
function doOtherStuffWithVariables (obj) {
for (const key in obj) {
console.log(`variable ${key} has a value of "${obj[key]}" and string length of ${obj[key].length}`)
}
}
As stated, there is no shortcut in Groovy. But if you want/need this
syntax, you can achieve this with Groovy
Macros.
E.g. a very straight forward attempt:
#Macro
static Expression map(MacroContext ctx, final Expression... exps) {
return new MapExpression(
exps.collect{
new MapEntryExpression(GeneralUtils.constX(it.getText()), it)
}
)
}
Usage:
def a = 42
def b = 666
println(map(a,b))
// → [a:42, b:666]
Unfortunately there's no direct counterpart in Groovy or Java for object deconstruction in JS. Although you can use map literals to write a similar code:
def doStuff( Map obj ) {
obj.each{ key, val ->
println "variable $key has a value of '${val}' and string length of ${obj[key].size()}"
}
}
def example(){
def a = 'a'
def b = 'bee'
def c = 'see'
doStuff( a:a, b:b, c:c )
}
I am not sure what you exactly want to do, but afaik, there is nothing similiar in java.
You could use tho the "new" methods in the java collections library:
String a = "a";
String b = "b";
String c = "c";
Map.of("a", a, "b", b, "c", c);
List.of(a,b,c)
But you should keep in mind, those methods are returning unmodifiable objects.
JavaDoc: Returns an unmodifiable list containing three elements. See Unmodifiable Lists for details.
As already said, this is not possible in Groovy, because as soon as you use a variable a in your code, then the value of that variable is passed and the name is forgotten.
However, I have also a solution which involves an intermediate object holding the properties to be interrogated:
def toMap(obj) {
obj.properties.collectEntries {
[(it.key):it.value]
}
}
def ex =
new Expando().tap {
a = 'A'
b = 'B'
}
assert toMap(ex) == [a:'A', b:'B']
The involves the dynamically expandable object feature.
Let's say that I have function Object f(String a, String b) and I want to call two different functions that return Optional Strings to get the parameters for f Optional<String> getA() and Optional<String> getB(). I can think of two solutions but neither look all that clean, especially when you have even more parameters:
1:
return getA().flatMap(
a -> getB().map(
b -> f(a,b)).get()
2:
Optional<String> a = getA();
Optional<String> b = getB();
if(a.isPresent() && b.isPresent()) {
return f(a.get(), b.get());
}
Is there a cleaner way to do this?
You've just stumbled upon a concept called lifting in functional programming, that enables you to lift regular functions (e.g. A -> B) into new domains (e.g. Optional<A> -> Optional<B>).
There's also a syntactic sugar for flatMapping and mapping more comfortably called the do notation in Haskell and similar languages, and for comprehension in Scala. It gives you a way to keep the flow linear and avoid nesting (that you were forced to go through in your example 1).
Java, unfortunately has nothing of the sort, as its functional programming capabilities are meager, and even Optional isn't really a first-class citizen (no standard API actually uses it).
So you're stuck with the approaches you've already discovered.
In case you're curious about the concepts mentioned above, read on.
Lifting
Assuming you have:
public String f(A a, B b) {
return b + "-" + a;
}
With its Scala equivalent:
def f(a: A, b: B) = b + "-" + a
Lifting f into Option (same as Optional in Java) would look like this (using Scalaz library, see here for Cats)
val lifted = Monad[Option].lift2(f)
lifted is now a function equivalent to:
public Optional<String> f(Optional<A> a, Optional<B> b) {
if(a.isPresent() && b.isPresent()) {
return Optional.of(b + "-" + a);
}
return Optional.empty;
}
Exactly what you're looking for, in 1 line, and works for any context (e.g. List, not just Option) and any function.
For comprehension / Do notation
Using for comprehension, your example would look like this (I think, my Scala is weak):
for {
a <- getA();
b <- getB();
} yield f(a, b)
And again, this is applicable to anything that can be flatMapped over, like List, Future etc.
You could stream the arguments and apply the condition only once, but whether or not this is more elegant than your solutions is in the eye of the beholder:
if (Stream.of(a, b).allMatch(Optional::isPresent)) {
return f(a.get(), b.get());
}
I'm of the opinion that if there is no good way to use Optional, then there is no reason to try to use it anyway.
I find this to be cleaner and simpler than your option 2:
String a = getA().orElse(null);
String b = getB().orElse(null);
if(a != null && b != null) {
return f(a, b);
}
If you are sure that a and b are both present (as your final call to get in solution 1 seems to suggest), I think it is pretty straightforward:
return f(getA().orElseThrow(() -> new NoSuchElementException("a not present")),
getB().orElseThrow(() -> new NoSuchElementException("b not present")));
If you aren’t sure that both are present, I would prefer your solution 1. It exploits Optional the best. Only I would not call get at the end, but rather orElse or what makes sense in your situation, for example:
return getA()
.flatMap(a -> getB().map(b -> f(a,b)))
.orElse("Not both present");
I'm need to make sure i understand correctly someone else code at work
this block sort this object: theObjectList
by the variable getId()
what do i need to do in order to add another variable to the sorting ? for example getName()
protected void fillData(List<AnyObject> theObjectList) {
Collections.sort(theObjectList, (A, B) -> A.getId() - B.getId());
/* more code */
}
You can use Comparators.comparing
Collections.sort(theObjectList,
Comparator.comparing(x -> x.getId()).andThen(x -> x.getName()));
Believe you'd need to understand and pickup lambda expressions. They have been introduced since jdk8.
I gotta make an array of method in Java because I have to call methods in a loop and the method called depends to the value of a figure (for example if figure is equal to 8, it's assert8(), etc...) I can do it in a simple if else if statement but it's not going to be clean.
So i wrote this :
boolean assertionsArray[] = {assert0(), assert1(), assert2(), assert3(), assert4(),
assert5(), assert6(), assert7(), assert8(), assert9()};
and now I'm searching to make that if my figure is 2, I call assertionsArray[2] etc...
Thank you !
What you've got is not an array of methods, it is an array of booleans. Each method is called at the moment the array is created, and the return values of these ten methods become values in the array.
If you would like to make an array of something that you can call, make an array of interface implementations that have a method returning boolean. The way you do this depends on the version of Java. Prior to Java 8, you would do it like this:
interface Predicate {
boolean test();
}
Predicate[] assertionsArray = new Predicate[] {
new Predicate() {public boolean test() {return assert0(); }}
, new Predicate() {public boolean test() {return assert1(); }}
, new Predicate() {public boolean test() {return assert2(); }}
...
, new Predicate() {public boolean test() {return assert9(); }}
};
Now you can call the assertions like this:
if (assertionsArray[figureIndex].test()) {
...
}
Starting with Java 8 you can use the predicate interface included with Java, and use lambdas instead of anonymous implementations:
Predicate<Object>[] assertionsArray = new Predicate<Object>[] {
o -> assert0(), o -> assert1(), o -> assert2(), o -> assert3(),
, o -> assert4(), ...
};
...
if (assertionsArray[figureIndex].test(null)) {
...
}
If you do this:
assert0();
You will call that method and the return value of that method comes into boolean array, which is not what you want.
When you want to call a method in an array, you are looking at the reflection package, however this is very, very bad practise to do. I am not going to provide sample code of that as that is not helping you.
As #Dragan pointed out, you are much better of using a switch statement, such as:
switch( figureNumber ) {
case 0: assert0(); break;
case 1: ... ; // etc
}
Putting aside that you cannot do that in java versions lower than 8, you'll be much better off calling a single method that can handle various input.
You provided sparse code, so I'm going to take a shot in the dark here and suggest a switch statement perharps.
What you are doing here will result in an array of boolean, with the results from all your assertX() methods, at the time of array creation.
What you are trying to do here reminds me of function pointers in C, which AFAIK is not possible in Java.
Consider this alternative;
Have one method called: assertByIntArgument(int n) which calls the appropriate assertX() method, based on the argument n
Something like this:
private boolean assertByInt(int n){
switch(n){
case 1: return assert1(); break;
case 2: return assert2(); break;
// ...
}
}
With Java 8, you could have the following:
Supplier<Boolean> assertionsArray = {
SomeClass::assert0(),
SomeOtherClass::assert1(),
SomeClass::assert2(),
SomeClass::assert3(),
SomeClass::assert4(),
SomeClass::assert5(),
SomeClass::assert6(),
SomeClass::assert7(),
SomeClass::assert8(),
this::assert9()
};
Then, in a loop or somewhere else:
boolean result = assertionsArray[i].get();
This answer is more of a 'as a matter of interest' than a real solution. The best solution in non-Java 8 environment is probably a switch. Another lead would have been reflection, as presented below, but please be aware that:
it is less efficient and performant;
it leaves your IDE (and compiler) blind and hinders you when navigating your code;
too much reflection makes code just impossible to read.
Use at your own risk.
If you want to stick to several methods though, you could use reflection.
If your methods are declared in MyClass, invoking a no-arg method would be the following:
MyClass.class.getDeclaredMethod("assert" + i).invoke();
If you need to pass arguments (let's say an int and a String), update to the following:
MyClass.class.getDeclaredMethod("assert" + i, int.class, String.class).invoke(3, "Hello");