Optional.ifAbsentThrow()? - java-8
Suppose I need to find a value of a certain order, then get its id, and then its localized-id. And if I can't do it, I want to throw and exception:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.map(Attribute::getId)
.map(Id::getLocalizedId)
.orElseThrow(() -> new RuntimeException("Could not get the localized id of the value of order " + order));
The problem is that the exception is not very detailed: it tells me I can't get the localized-id, but not why.
I miss some Optional.ifAbsentThrow method that would allow me to do this:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.ifAbsentThrow(() -> new RuntimeException("Could not find value of order " + order));
.map(Attribute::getId)
.ifAbsentThrow(() -> new RuntimeException("Value of order " + order + " has no id"));
.map(Id::getLocalizedId)
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
To solve this problem, I have created the following ifAbsentThrow method:
public static <T, X extends RuntimeException> Predicate<T> ifAbsentThrow(Supplier<? extends X> exceptionSupplier) throws RuntimeException {
return valor -> {
if (valor == null) throw exceptionSupplier.get();
return true;
};
}
And I use it like this:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.filter(ifAbsentThrow(() -> new RuntimeException("Could not find value of order " + order));
.map(Attribute::getId)
.filter(ifAbsentThrow(() -> new RuntimeException("Value of order " + order + " has no id"));
.map(Id::getLocalizedId)
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
My Questions:
1) Am I missing something here? Is Optional really missing this
functionality or I shouldn't be doing this for some reason?
2) Is there a better, recommended way of throwing more detailed exceptions
for missing values?
Edit: It now seems to me that Optional.ifAbsentThrow does not exist because it would be a way of dealing with null values, and Optional is all about not using null values in the first place. Optional clearly doesn't play well with null values, it gets verbose if you mix them. However, in the real world I find it difficult to deal with this all-or-nothing proposition: Some code gets translated to Optionals, while other remains using nullable values. To help me mix them, and refactor nullables to Optionals only when necessary, I believe I will be using the GetNonNull class below, built upon knowledge I gained from #Alex and #Holgers answers in this page.
Optional is meant to encapsulate a possibly absent value. If you perform an operation like ifAbsentThrow there is no point in carrying the value as an Optional as you already know it’s not absent on normal completion. So orElseThrow does what you intend but returns an ordinary object as it’s not optional anymore.
Of course, you can apply a function to an ordinary object and wrap its result into an Optional again, as Alex suggested, but ask yourself whether this is really an improvement over the straight-forward code:
Attribute a=values.stream().filter(value -> value.getOrder("order") == order).findAny()
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order));
Id id=a.getId();
if(id==null)
throw new RuntimeException("Value of order " + order + " has no id");
String name=id.getName();
if(name==null)
throw new RuntimeException(
"Could get the id but not the localized id of the value of order " + order);
return name;
You can also create a utility method providing the operation of applying a function and throwing appropriately if the function returned null:
static <T,R, E extends Throwable> R get(T o, Function<T,R> f, Supplier<E> s) throws E {
return Optional.ofNullable(f.apply(o)).orElseThrow(s);
}
using this method, your operation becomes:
return get(ContainingClass.<Attribute,Id,RuntimeException>get(
values.stream().filter(value -> value.getOrder("order") == order).findAny()
.orElseThrow( () -> new RuntimeException("Could not find value of order " + order)),
Attribute::getId,() -> new RuntimeException("Value of order " + order + " has no id")),
Id::getName, () -> new RuntimeException(
"Could get the id but not the localized id of the value of order " + order));
(Unfortunately, the type inference of the compiler hit its limit here)
The last resort would be the creation of an alternative to Optional which does not only carry a possibly absent value but an optional error:
public final class Failable<T,E extends Throwable> {
private final T value;
private final E failure;
private Failable(T value, E failure) {
this.value=value;
this.failure=failure;
if(value==null && failure==null) throw new NullPointerException();
}
public T get() throws E {
if(failure!=null) throw failure;
return value;
}
public <R> Failable<R,E> map(Function<T,R> f, Supplier<E> s) {
if(value!=null) {
R result=f.apply(value);
return new Failable<>(result, result!=null? null: s.get());
}
// already failed, types of R and T are irrelevant
#SuppressWarnings("unchecked") Failable<R,E> f0=(Failable)this;
return f0;
}
public static <T,E extends Throwable> Failable<T,E> of(Optional<T> o, Supplier<E> s) {
return o.map(t -> new Failable<>(t, (E)null))
.orElseGet(()->new Failable<>(null, s.get()));
}
}
Using this class, you could code your operation as
return Failable.of(
values.stream().filter(value -> value.getOrder("order") == order).findAny(),
() -> new RuntimeException("Could not find value of order " + order))
.map(Attribute::getId, ()->new RuntimeException("Value of order "+order+" has no id"))
.map(Id::getName, ()->new RuntimeException(
"Could get the id but not the localized id of the value of order " + order)).get();
Yes, Optional does not have an ifAbsentThrow method which returns the Optional if it is present. The closest is orElseThrow which returns the value from the optional.
Since your way doesn't actually work, there certainly is a better way to do it.
It doesn't work because this is the implementation of Optional#filter:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
As you can see, it doesn't use the Predicate if it is not present, so your filters are doing nothing.
One way you could do it is to use orElseThrow and then re-wrap the result after applying your mapping function with ofNullable:
Optional<Attribute> o = //get your first optional from the stream.
return Optional.ofNullable(Optional.ofNullable(
o.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId())
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName())
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
You could also break that up into separate statements if you think that would be more readable.
Another way would be to change Attribute#getId and Id#getName to return Optionals instead of null. Then it would look like this:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.getId()
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.getName()
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
I would prefer this way because you don't need to re-wrap the return values with ofNullable and it lets other people calling those methods know that the return values are optional, but if you can't change them then the first way would work fine.
The hypothetical ifAbsentThrow(...) method can be expressed with existing methods of Optional like this:
.map(Optional::of).orElseThrow(...)
Then your original example becomes:
return values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny()
.map(Optional::of)
.orElseThrow(() -> new RuntimeException("Could not find value of order " + order))
.map(Attribute::getId)
.map(Optional::of)
.orElseThrow(() -> new RuntimeException("Value of order " + order + " has no id"))
.map(Id::getLocalizedId)
.orElseThrow(() -> new RuntimeException("Could get the id but not the localized id of the value of order " + order));
Based on the knowledge I gained from #Alex and #Holgers answers in this page,
I have developed the following GetNonNull class, focused on readability:
Optional<Value> value = values.stream()
.filter(value -> value.getOrder("order") == order)
.findAny();
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
I find this functional code very easy to read, and it concentrates all exception handling code together (no need to
add orElseThrow to the end of the stream). The GetNonNull name implies that the end result will never be null.
Compare it with the alternative imperative code:
if (valor == null) throw new RuntimeException("Got no value.");
Attribute attribute = valor.getAttribute();
if (attribute == null) throw new RuntimeException("Got value, but no attribute.");
Id id = attribute.getId();
if (id == null) throw new RuntimeException("Got value and attribute, but no id.");
String localizedId = id.getLocalizedId();
if (localizedId == null) throw new RuntimeException("Got value, attribute and id, but no localized id.");
return localizedId;
Instead of throwing, you may also return an Optional:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOptional(Id::getLocalizedId); // Changed here.
Or you may return a non-null default value:
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.getOrDefault(Id::getLocalizedId, "DEFAULT"); // Changed here.
It is also Optional/null agnostic, i.e., nothing changes if the initial value is a regular nullable value, instead of an Optional:
Value value = ...; // Not an Optional.
return GetNonNull
.mapOrThrow(value, () -> new RuntimeException("Got no value."))
.mapOrThrow(Value::getAttribute, () -> new RuntimeException("Got value, but no attribute."))
.mapOrThrow(Attribute::getId, () -> new RuntimeException("Got value and attribute, but no id."))
.mapOrThrow(Id::getLocalizedId, () -> new RuntimeException("Got value, attribute and id, but no localized id."))
.get();
You can also use it as a simple functional get-default-value idiom. This:
Value value = ...;
if (value != null) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
May be written as:
// Shorter and more readable then Optional.ofNullable(value).orElse(default).
// Also not the same, because here a NullPointerException is raised if default is null.
return GetNonNull.getOrDefault(value, default);
And this:
Optional<Value> value = ...;
if (value.isPresent()) return value;
else if (default != null) return default;
else throw new NullPointerExeption();
May also be written exactly the same:
return GetNonNull.getOrDefault(value, default);
Since the GetNonNull class is compatible with both nullables and Optionals, if some legacy imperative
code that use nullable values gets later refactored to use Optionals, the GetNonNull usage needs not to be changed.
Here it is:
public final class GetNonNull<T, E extends Throwable> {
private final T value;
private final E failure;
private GetNonNull(T value, E failure) {
this.value = value;
this.failure = failure;
if ((value == null) && (failure == null)) throw new NullPointerException();
}
public T get() throws E {
if (failure != null) throw failure;
return value;
}
public <R> Optional<R> getOptional(Function<T, R> f) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
return Optional.ofNullable(result);
}
return Optional.empty();
}
public static <R> R getOrDefault(R o1, Supplier<R> supplier) {
if (o1 != null) return o1;
R result = supplier.get();
if (result != null) return result;
else throw new NullPointerException();
}
public static <R> R getOrDefault(R o1, R o2) {
if (o1 != null) return o1;
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public static <R> R getOrDefault(Optional<R> o1, R o2) {
if (o1.isPresent()) return o1.get();
else if (o2 != null) return o2;
else throw new NullPointerException();
}
public <R> R getOrDefault(Function<T, R> f, R o) throws E {
if (failure != null) throw failure;
if (value != null) {
R result = f.apply(value);
if (result != null) return result;
else return o;
}
return o;
}
public <R> GetNonNull<R, E> mapOrThrow(Function<T, R> f, Supplier<E> s) {
if (value != null) {
R result = f.apply(value);
return new GetNonNull<>(result, (result != null) ? null : s.get());
}
return (GetNonNull)this;
}
public static <T, E extends Throwable> GetNonNull<T, E> getOrThrow(Optional<T> o, Supplier<E> s) {
return o.map(t -> new GetNonNull<>(t, (E)null)).orElseGet(() -> new GetNonNull<>(null, s.get()));
}
public static <T, E extends Throwable> GetNonNull<T, E> mapOrThrow(T o, Supplier<E> s) {
return getOrThrow(Optional.ofNullable(o), s);
}
}
Related
Find null Type's name in Optional method chain(through map operation) for multilevel POJO
I have similar class structure. class Request { Level1 level1; } class Level1 { Level2 level2; String data; } class Level2 { Level3 level3; String data; } class Level3 { Level4 level4; String data; } class Level4 { String data; } Request r = new Request(); r.level1 = new Level1(); r.level1.level2 = new Level2(); r.level1.level2.level3 = null;//new Level3(); //r.level1.level2.level3.level4 = new Level4(); //r.level1.level2.level3.level4.data = "level4Data"; and to get data from nested fields I do following Benefit of using Optional being I don't have to worry about checking null at each level in object hierarchy String level4Data = Optional.ofNullable(r) .map(req -> req.level1) .map(l1 -> l1.level2) .map(l2 -> l2.level3) .map(l3 -> l3.level4) .map(l4 -> l4.data) .orElse(null); System.out.println("level4Data: " + level4Data); but again if I want to log reason behind level4Data being null, I have to do following/I don't any better if (level4Data == null) { if (r == null) System.out.println("request was null"); else if (r.level1 == null) System.out.println("level1 was null"); else if (r.level1.level2 == null) System.out.println("level2 was null"); else if (r.level1.level2.level3 == null) System.out.println("level3 was null"); else if (r.level1.level2.level3.level4 == null) System.out.println("level4 was null"); else if (r.level1.level2.level3.level4.data == null) System.out.println("level4.data was null"); } is there more elegant/efficient way of doing this as it defeats benefits of using Optional in first place Thank you for your time and inputs
Optional doesn't have a peek method like in Stream API. For your use case, you can write a wrapper that will do the additional job: // logging wrapper static <T, R> Function<T, R> logIfNull(Function<? super T, ? extends R> function, String message) { return input -> { R result; if ((result = function.apply(input)) == null) System.out.println("logIfNull :: Null found. " + message); return result; }; } // usage String level4Data = Optional.ofNullable(r) .map(logIfNull(req -> req.level1, "req.level1")) .map(logIfNull(l1 -> l1.level2, "l1.level2")) .map(logIfNull(l2 -> l2.level3, "l2.level3")) .map(logIfNull(l3 -> l3.level4, "l3.level4")) .map(logIfNull(l4 -> l4.data, "l4.data")) .orElse(null);
Observable that combines behavior of groupby with combinelatest and exhibits "outer join" behavior
I'm trying to use reactive paradigm to create an observable that acts like a combination of "group by" and combinelatest. I have two source observables that have a shared joining key, like in the following two data structures. class Foo { string Key; string Funky; } class Bar { string Key; string Town; } What I want is an observable that yields me the latest combination of these two joined on InstrumentID. The end result should look something like: class Target { string Key; string Funky; string Town; } and exhibits an "outer join" like behavior, meaning the first sequence to produce a new "key" will yield a Target class with the other side being null, and then once the other side also produces the same joining key, the latest from both sides is yielded whenever there's a new value in either sequence for the given key.
Let's say your foo$ stream emits values of type Foo, and bar$ stream emits values of Bar. Here is how you can combine them: combineLatest([ foo$, bar$ // use startWith(null) to ensure combineLatest will emit as soon as foo$ emits, not waiting for bar$ to emit its first value .pipe(startWith(null)) ]).pipe( map(([foo, bar]) => ({ // always keep all properties from foo ...foo, // only add properties from bar if it has the matching Key ...(bar && bar.Key === foo.Key ? bar : null) })) )
This may not be "cosher" by some standards but works for what I need it to do. Posting for anyone looking for same functionality (.NET Version of RX) public static class Extensions { public static IObservable<TResult> CombineLatestGrouped<TFirst,TSecond,TKey, TResult>( this IObservable<TFirst> first, IObservable<TSecond> second, Func<TFirst, TKey> firstKeySelector, Func<TSecond, TKey> secondKeySelector, Func<TKey,TFirst,TSecond,TResult> resultSelector) { var dic = new ConcurrentDictionary<TKey,Tuple<TFirst,TSecond>>(); return Observable.Create<TResult>(obs => { var d1 = first .Select(x => { var key = firstKeySelector(x); var tuple = dic.AddOrUpdate( key, addValueFactory: key => Tuple.Create(x, default(TSecond)), updateValueFactory: (key, existing) => Tuple.Create(x, existing.Item2)); return resultSelector(key, tuple.Item1, tuple.Item2); }) .Subscribe(obs); var d2 = second .Select(x => { var key = secondKeySelector(x); var tuple = dic.AddOrUpdate( key, addValueFactory: key => Tuple.Create(default(TFirst), x), updateValueFactory: (key, existing) => Tuple.Create(existing.Item1, x)); return resultSelector(key, tuple.Item1, tuple.Item2); }) .Subscribe(obs); return new CompositeDisposable(d1, d2); }); } }
As I see it, you would like following: a new "key" will yield a Target class with the other side being null When left or right side emmits a NEW key (prev: null or different) , and then once the other side also produces the same joining key, precondition: a stream emitted a value -- other stream now emits a value and the key for left and right eq the latest from both sides is yielded whenever there's a new value in either sequence for the given key. emit full target (composed of left, right) on each left,right emit, when a value of left,right changes distinctly RxJava2 solution for my assumption: #Test void test2() { PublishSubject<Foo> foo$ = PublishSubject.create(); PublishSubject<Bar> bar$ = PublishSubject.create(); Observable<Target> target$ = Observable.merge(Arrays.asList(foo$, bar$)) // filter invalid values .filter(hasId -> hasId.key() != null) .scan(Target.NULL, (prev, change) -> { // when prev. target and current value#key are eq -> emit composed value if (change.key().equals(prev.key)) { return composedTarget(prev, change); } else if (change instanceof Foo) { return Target.fromFoo((Foo) change); } else if (change instanceof Bar) { return Target.fromBar((Bar) change); } return prev; }).filter(target -> target != Target.NULL) .distinctUntilChanged(); TestObserver<Target> test = target$.test(); // emit foo$.onNext(new Foo("123", "f1")); // emit bar$.onNext(new Bar("123", "f2")); // emit bar$.onNext(new Bar("123", "f3")); // skipped foo$.onNext(new Foo("123", "f1")); // emit foo$.onNext(new Foo("123", "f5")); // emit foo$.onNext(new Foo("key", "value")); // emit foo$.onNext(new Foo("key2", "value2")); // emit bar$.onNext(new Bar("bar2", "Berlin")); // emit foo$.onNext(new Foo("foo2", "Funkeey")); test.assertValues( new Target("123", "f1", null), new Target("123", "f1", "f2"), new Target("123", "f1", "f3"), new Target("123", "f5", "f3"), new Target("key", "value", null), new Target("key2", "value2", null), new Target("bar2", null, "Berlin"), new Target("foo2", "Funkeey", null) ); } private Target composedTarget(Target prev, HasId change) { if (change instanceof Foo) { Foo foo = (Foo) change; return new Target(prev.key, foo.funky, prev.town); } if (change instanceof Bar) { Bar bar = (Bar) change; return new Target(prev.key, prev.funky, bar.town); } return prev; } Domain-Classes interface HasId { String key(); } static final class Foo implements HasId { final String key; final String funky; Foo(String key, String funky) { this.key = key; this.funky = funky; } #Override public String key() { return key; } } static final class Bar implements HasId { String key; String town; Bar(String key, String town) { this.key = key; this.town = town; } #Override public String key() { return key; } } static final class Target { private static final Target NULL = new Target(null, null, null); final String key; final String funky; final String town; Target(String key, String funky, String town) { this.key = key; this.funky = funky; this.town = town; } static Target fromFoo(Foo foo) { return new Target(foo.key, foo.funky, null); } static Target fromBar(Bar bar) { return new Target(bar.key, null, bar.town); } #Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Target target = (Target) o; return key.equals(target.key) && Objects.equals(funky, target.funky) && Objects.equals(town, target.town); } #Override public int hashCode() { return Objects.hash(key, funky, town); } #Override public String toString() { return "Target{" + "key='" + key + '\'' + ", funky='" + funky + '\'' + ", town='" + town + '\'' + '}'; } } Please correct my assumptions, if I am mistaken. The solution could be implemented way better in C# with pattern-matching. Actually if C# has union types like F#, that would be best.
Xposed - Return class constructor
Decompilled method: private static l c(String str, String str2, String str3, String str4) { l lVar; k kVar = (k) m.get(str); j jVar = (j) l.get(str); if (kVar != null) { lVar = new l(kVar, str2, str3); } else if (jVar != null) { lVar = new l(jVar, str2, str3); } else { lVar = new l(j.GENERIC, str2, str3); } lVar.a(str4); return lVar; } How to use Xposed to return new l (jVar, str2, str3) with its specific values? The beginning of the code I have is: try { findAndHookMethod("com.xiaomi.hm.health.ui.smartplay.h", lpparam.classLoader, "c", String.class, String.class, String.class, String.class, new XC_MethodHook() { #Override protected void afterHookedMethod(MethodHookParam param) { String pkg = (String) param.args[0]; if (pkg == "com.perm.kate_new_6"){ return ???; } } }); } catch (Throwable t) { t.printStackTrace(); }
The XC_MethodHook's afterHookedMethod method needs to return void. I.e., the return of the hooked method needs be be set via setResult method of XC_MethodHook instead. Internally it sets returnEarly to true which is checked in XposedBridge, preventing the original method code from executing, as well as any other hooks on the method. If you just want to access whatever the method was originally going to return then getResult() should do. If you need to return anything else, you can use reflection or Xposed's helpers (findClass) to retrieve the l, k and j classes, replicate the code if needed, create a new instance and return it via setResult. Alternatively you can use a XC_MethodReplacement hook instead as you will likely replicate its functionality anyways.
String stream joining: stream has already been operated upon or closed
Using java8 to concatenate an object certain field value with a "_". The last line in the code throws an "stream has already been operated upon or closed". Stream<Field> fields = ... Stream<String> exclusions = ... Stream<String> stringStream = fields.filter(f -> exclusions.anyMatch(e -> e.equals(f.getName()))) .map(f -> { f.setAccessible(true); Object value = null; try { value = f.get(obj); } catch (IllegalAccessException e) { e.printStackTrace(); } return value; }) .filter(v -> v != null) .map(Object::toString); String suffix = stringStream.collect(Collectors.joining("_")); EDIT: I have tried this with: List<Foo> list = new ArrayList<>(); list.stream().filter(item -> item != null).map(item -> { String value = null; return value; }).filter(item -> item != null).map(item -> { String value = null; return value; }).collect(Collectors.joining("")); And there is no such exception.
How many times is the first filter called? More then once right? The exclusions that you use in the first call to filter is consumed via anyMatch; thus the second time you try to use it - you get the exception. The way to solve it, would be to stream on every single filter operation: filter(f -> sourceOfExclusions.stream().anyMatch...
Java8: Filter and map on same method output
We are trying to refactor below code to java 8: List<String> list = new ArrayList<>(); Iterator<Obj> i = x.iterator(); while (i.hasNext()) { String y = m(i.next().getKey()); if (y != null) { list.add(y); } } return list; So far we have come up with: return x.stream() .filter(s -> m(s.getKey()) != null) .map(t -> m(t.getKey())) .collect(Collectors.toList()); But the method m() is being invoked twice here. Is there any way around?
Well you can do the filtering after the mapping step: x.stream() .map(s -> m(s.getKey())) .filter(Objects::nonNull) .collect(Collectors.toList());