I need to chain two observables, the second depends on the first.
So what I have is:
Observable 1 -> petition returns Observable<TvShow>
//kotlin
fun getTvShow(): Observable<TvShow> {
return retrofitPetitionGetShow()...
}
//java
Observable<TvShow> getTvShow(){
return retrofitPetitionGetShow()...
}
Observable 2 -> returns Single<List<Season>>
Observable.range(1, TvShow.totalSeasons)
.flatMap { seasonNumber: Int ->
retrofitPetitionGetSeason(seasonNumber)....
}.toList()
What I need is the result of the second observable (List<Season>) to be added to the TvShow object TvShow.setList(List<Season>) and then return it.
Thank you in advance
Basing on provided information in comments you can try with the following code (it is Java code but it should be easy to convert that to Kotlin):
private Observable<TvShow> getTvShow() {
return retrofitPetitionGetShow();
}
private Single<List<Season>> getSeasons(TvShow tvShow) {
return Observable.range(1, tvShow.getTotalSeasons())
.flatMap(seasonNumber -> retrofitPetitionGetSeason(seasonNumber))
.toList();
}
public Observable<TvShow> chainObservables() {
return getTvShow()
.flatMap(tvShow -> getSeasons(tvShow).map(tvShow::withSeasons).toObservable());
}
IMPORTANT!
In reactive/functional way you should not modify objects, but create the new one (in your case, there is an update of tvShow with seasons list). There is a tvShow::withSeasons method reference which is implemented in this way:
public TvShow withSeasons(List<Season> seasons) {
return this.seasons == seasons ? this : new TvShow(this.name, this.totalSeasons, seasons);
}
Related
public Single<Content> createContent(final Content content) {
BackendACL acl = new BackendACL();
acl.setPublicRead(false);
acl.setPublicWrite(false);
content.setAcl(acl);
return content.create().flatMap(backendEntity -> {
Content newContent = (Content) backendEntity;
newContent.setEntityId(backendEntity.getEntityId());
newContent.setSchema(content.getSchema());
return Single.just(newContent);
}).flatMap(content1 -> {
return content1.setLink("schema", content1.getSchema().getEntityId());
}).flatMap(isLinked -> {
// Code section 1
//return content1.setLink("user", getLoggedInUser().getEntityId());
return Single.just(true); // just a dummy to illustrate
}).flatMap(isLinked -> {
return Single.just(content);
// Code section 2
// should be: return Single.jus(content1);
});
}
In the code above, what is the solution to use the content1 variable in Code section 1 and Code section 2?
Between one operator and another you can only emit one object type.
In your situation you are emitting a boolean value to code section 1, but you also want to have access to the Content instance.
The solution is to wrap both values (Content object and boolean value) in a single class and emit that class.
Create a class to wrap the emission of Content and the result of setLink.
class Pair {
private final Content content;
private final boolean isLinked;
private Pair(Content content, boolean isLinked) {
this.content = content;
this. isLinked = isLinked;
}
public Content getContent() {
return content;
}
public boolean isLinked() {
return isLinked;
}
}
Then change your code to emit that class:
return content.create().flatMap(backendEntity -> {
Content newContent = (Content) backendEntity;
newContent.setEntityId(backendEntity.getEntityId());
newContent.setSchema(content.getSchema());
return Single.just(newContent);
}).flatMap(content1 -> {
return content1.setLink("schema", content1.getSchema().getEntityId())
.flatMap(isLinked -> Single.just(new Pair(content1, isLinked)));
}).flatMap(pair -> {
// Code section 1
// ** here you can access pair.getContent() and pair.isLinked()
return Single.just(true); // just a dummy to illustrate
})
Ps: instead of creating your own Pair class, check one of the options from this thread. If you are using Kotlin, there is a Pair class.
This is an offshoot of my other question: How to chain Optional#ifPresent() in lambda without nesting?
However, the problem now is how to provide a lambda solution where all of the optional values are available at the innermost scope:
B b = procA().flatMap(this::procB).orElseThrow(SomeException::new);
// Value from procA() is not available.
My original code was:
void SomeMethod() {
procA().ifPresent(a -> {
procB(a).ifPresent(b -> {
// Do something with a and b
return;
});
});
throw new SomeException();
}
I understand that the return at the innermost scope is wrong. The new flatMap example illustrates the correct behavior.
I am using ifPresent() instead of get() to avoid potential runtime exceptions where I might fail to check whether the value of an optional isPresent().
I find this question very interesting as chained calls with potential null returns are a common nuisance, and Optional can shorten the usual null check chain a lot. But the issue there is that the nature of the functional stream methods hides the intermediate values in the mapping functions. Nesting is a way to keep them available, but can also get annoying if the length of the call chain grows, as you have realized.
I cannot think of an easy and lightweight solution, but if the nature of your project leads to these situations regularly, this util class could help:
public static class ChainedOptional<T>
{
private final List<Object> intermediates;
private final Optional<T> delegate;
private ChainedOptional(List<Object> previousValues, Optional<T> delegate)
{
this.intermediates = new ArrayList<>(previousValues);
intermediates.add(delegate.orElse(null));
this.delegate = delegate;
}
public static <T> ChainedOptional<T> of(T value)
{
return of(Optional.ofNullable(value));
}
public static <T> ChainedOptional<T> of(Optional<T> delegate)
{
return new ChainedOptional<>(new ArrayList<>(), delegate);
}
public <R> ChainedOptional<R> map(Function<T, R> mapper)
{
return new ChainedOptional<>(intermediates, delegate.map(mapper));
}
public ChainedOptional<T> ifPresent(Consumer<T> consumer)
{
delegate.ifPresent(consumer);
return this;
}
public ChainedOptional<T> ifPresent(BiConsumer<List<Object>, T> consumer)
{
delegate.ifPresent(value -> consumer.accept(intermediates, value));
return this;
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
throws X
{
return delegate.orElseThrow(exceptionSupplier);
}
public <X extends Throwable> T orElseThrow(Function<List<Object>, X> exceptionSupplier)
throws X
{
return orElseThrow(() -> exceptionSupplier.apply(intermediates));
}
}
You use it by wrapping an Optional or a plain value. When you then use the map method to chain method calls, it will provide a new ChainedOptional while storing the current value in a list. At the end (ifPresent, orElseThrow), you will not only get the last value, but also the list of all intermediate values. Since it is not known how many calls will be chained, I did not find a way to store those values in a type-safe way, though.
See examples here:
ChainedOptional.of(1)
.map(s -> s + 1)
.map(s -> "hello world")
.map(s -> (String) null)
.map(String::length)
.ifPresent((intermediates, result) -> {
System.out.println(intermediates);
System.out.println("Result: " + result);
})
.orElseThrow(intermediates -> {
System.err.println(intermediates);
return new NoSuchElementException();
});
// [1, 2, hello world, null, null]
// Exception in thread "main" java.util.NoSuchElementException
// at ...
ChainedOptional.of(1)
.map(s -> s + 1)
.map(s -> "hello world")
// .map(s -> (String) null)
.map(String::length)
.ifPresent((intermediates, result) -> {
System.out.println(intermediates);
System.out.println("Result: " + result);
})
.orElseThrow(intermediates -> {
System.err.println(intermediates);
return new NoSuchElementException();
});
// [1, 2, hello world, 11]
// Result: 11
Hope this helps. Let me know if you come up with a nicer solution.
I am trying to wrap my head around generic and functions... what I am trying to achieve: Passing function name as a string to get it executed:
I want to do Wrapper.useFunction("eleven") or Wrapper.useFunction("ten")
public class Wrapper<T> {
public F useFunction(Function<F, F> function) {
return function.apply(F);
}
Function<F, String> ten = s -> "10";
Function<F, String> eleven = s -> "11";
}
But this code not even close to compiling. Maybe it doesn't make any sense. Any suggestions?
If you have a finite set of functions which you would like to be able to call I would recommend building a Map which maps Strings to instances of Runnable (or similar functional interfaces). Your useFunction method may then look up the function implementation in the Map and call it if it exists.
Example:
public class SomeClass {
private final Map<String, Runnable> methods = new HashMap<>();
{
methods.put("helloworld", () -> {
System.out.println("Hello World!");
});
methods.put("test", () -> {
System.out.println("test!");
});
methods.put("doStuff", () -> {
System.out.println("doStuff!");
});
}
public void perform(String code) {
methods.getOrDefault(code,
() -> {
System.err.println("No such Method: "+code);
})
.run();
}
}
If you want to call arbitrary methods you should probably use Reflection as stated by others.
I want to replace the following code using java8 Optional:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
The following pseudocode does not work as there is no orElseRun method, but anyways it illustrates my purpose:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
With Java 9 or higher, ifPresentOrElse is most likely what you want:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
Currying using vavr or alike might get even neater code, but I haven't tried yet.
I don't think you can do it in a single statement. Better do:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
For Java 8 Spring Data offers ifPresentOrElse from "Utility methods to work with Optionals" to achieve what you want.
Example would be:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
You will have to split this into multiple statements. Here is one way to do that:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
obj.ifPresent(o -> o.setAvailable(true));
return obj;
Another way (possibly over-engineered) is to use map:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> {o.setAvailable(true); return o;});
If obj.setAvailable conveniently returns obj, then you can simply the second example to:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
There is an .orElseRun method, but it is called .orElseGet.
The main problem with your pseudocode is that .isPresent doesn't return an Optional<>. But .map returns an Optional<> which has the orElseGet method.
If you really want to do this in one statement this is possible:
public Optional<Obj> getObjectFromDB() {
return dao.find()
.map( obj -> {
obj.setAvailable(true);
return Optional.of(obj);
})
.orElseGet( () -> {
logger.fatal("Object not available");
return Optional.empty();
});
}
But this is even clunkier than what you had before.
First of all, your dao.find() should either return an Optional<Obj> or you will have to create one.
e.g.
Optional<Obj> = dao.find();
or you can do it yourself like:
Optional<Obj> = Optional.ofNullable(dao.find());
this one will return Optional<Obj> if present or Optional.empty() if not present.
So now let's get to the solution,
public Obj getObjectFromDB() {
return Optional.ofNullable(dao.find()).flatMap(ob -> {
ob.setAvailable(true);
return Optional.of(ob);
}).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
}
This is the one liner you're looking for :)
For those of you who want to execute a side-effect only if an optional is absent
i.e. an equivalent of ifAbsent() or ifNotPresent() here is a slight modification to the great answers already provided.
myOptional.ifPresentOrElse(x -> {}, () -> {
// logic goes here
})
Title: "How to execute logic on Optional if not present?"
Answer:
Use orElseGet() as a workaround for the missing ifNotPresent(). And since it expects us to return something just return
null.
Optional.empty().orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
or
Optional.ofNullable(null).orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
I also use it to easily implement the singleton pattern with lazy initialization.
public class Settings {
private Settings(){}
private static Settings instance;
public static synchronized Settings getInstance(){
Optional.ofNullable(instance).orElseGet(() -> instance = new Settings());
return instance;
}
}
Of course the getInstance() content can be written in one line by directly returning the first statement, but I wanted to demonstrate the use of orElseGet() as an ifNotPresent().
I was able to came up with a couple of "one line" solutions, for example:
obj.map(o -> (Runnable) () -> o.setAvailable(true))
.orElse(() -> logger.fatal("Object not available"))
.run();
or
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
.orElse(o -> logger.fatal("Object not available"))
.accept(null);
or
obj.map(o -> (Supplier<Object>) () -> {
o.setAvailable(true);
return null;
}).orElse(() () -> {
logger.fatal("Object not available")
return null;
}).get();
It doesn't look very nice, something like orElseRun would be much better, but I think that option with Runnable is acceptable if you really want one line solution.
With Java 8 Optional it can be done with:
Optional<Obj> obj = dao.find();
obj.map(obj.setAvailable(true)).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
In order to get the value from one call, or do an extra call if the previous returned an empty value, you can chain the commands.
public Optional<Obj> getObjectFromDB() {
return dao.find().or(() -> dao.findBySomethingElse());
}
You need Optional.isPresent() and orElse(). Your snippet won;t work because it doesn't return anything if not present.
The point of Optional is to return it from the method.
ifPresentOrElse can handle cases of nullpointers as well. Easy approach.
Optional.ofNullable(null)
.ifPresentOrElse(name -> System.out.println("my name is "+ name),
()->System.out.println("no name or was a null pointer"));
I suppose you cannot change the dao.find() method to return an instance of Optional<Obj>, so you have to create the appropriate one yourself.
The following code should help you out. I've create the class OptionalAction,
which provides the if-else mechanism for you.
public class OptionalTest
{
public static Optional<DbObject> getObjectFromDb()
{
// doa.find()
DbObject v = find();
// create appropriate Optional
Optional<DbObject> object = Optional.ofNullable(v);
// #formatter:off
OptionalAction.
ifPresent(object)
.then(o -> o.setAvailable(true))
.elseDo(o -> System.out.println("Fatal! Object not available!"));
// #formatter:on
return object;
}
public static void main(String[] args)
{
Optional<DbObject> object = getObjectFromDb();
if (object.isPresent())
System.out.println(object.get());
else
System.out.println("There is no object!");
}
// find may return null
public static DbObject find()
{
return (Math.random() > 0.5) ? null : new DbObject();
}
static class DbObject
{
private boolean available = false;
public boolean isAvailable()
{
return available;
}
public void setAvailable(boolean available)
{
this.available = available;
}
#Override
public String toString()
{
return "DbObject [available=" + available + "]";
}
}
static class OptionalAction
{
public static <T> IfAction<T> ifPresent(Optional<T> optional)
{
return new IfAction<>(optional);
}
private static class IfAction<T>
{
private final Optional<T> optional;
public IfAction(Optional<T> optional)
{
this.optional = optional;
}
public ElseAction<T> then(Consumer<? super T> consumer)
{
if (optional.isPresent())
consumer.accept(optional.get());
return new ElseAction<>(optional);
}
}
private static class ElseAction<T>
{
private final Optional<T> optional;
public ElseAction(Optional<T> optional)
{
this.optional = optional;
}
public void elseDo(Consumer<? super T> consumer)
{
if (!optional.isPresent())
consumer.accept(null);
}
}
}
}
I have three Observables which I combine with combineLastest:
Observable<String> o1 = Observable.just("1");
Observable<String> o2 = Observable.just("2");
Observable<String> o3 = Observable.just("3");
Observable.combineLatest(o1, o2, o3, new Func3<String, String, String, Object>() {
#Override
public Object call(String s, String s2, String s3) {
return null;
}
});
I want to be notified about the first emission of one of the Observables without ignoring the later emissions, which I guess first operator would do. Is there a convenient operator for that like (example):
o1.doOnFirst(new Func1<String, Void>() {
#Override
public Void call(String s) {
return null;
}
})
I think you can have a practical doOnFirst with a simple take if you're handling a stream:
public static <T> Observable<T> withDoOnFirst(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source);
}
This way the action is only bound to the first item.
This could be changed to handle observables which are not backed by streams adding skip to skip the already taken items:
public static <T> Observable<T> withDoOnFirstNonStream(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source.skip(1));
}
For convenience, I created these extension functions for Flowable and Observable.
Note, that with doOnFirst() the action will be called before the first element emission, whilst doAfterFirst() will firstly emit the first item and then perform the action.
fun <T> Observable<T>.doOnFirst(onFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doOnFirst(onFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Observable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
Usage is as simple as this:
Flowable.fromArray(1, 2, 3)
.doOnFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// First 1
// 1
// 2
// 3
And:
Flowable.fromArray(1, 2, 3)
.doAfterFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// 1
// First 1
// 2
// 3
There are a couple of solutions I can think of.
The first one is an ugly but simple hack of doOnNext. Just add a boolean field to the Action1 indicating whether the first item has been received. Once received, do whatever it is you want to do, and flip the boolean. For example:
Observable.just("1").doOnNext(new Action1<String>() {
boolean first = true;
#Override
public void call(String t) {
if (first) {
// Do soemthing
first = false;
}
}
});
The second one is to subscribe twice on the observable you want to monitor using publish or share(), with one of those publications going through first (depending on whether you want to manually connect to the published observable). You'll end up with two separate observables that emit the same items, only the first one will stop after the first emission:
ConnectableObservable<String> o1 = Observable.just("1").publish();
o1.first().subscribe(System.out::println); //Subscirbed only to the first item
o1.subscribe(System.out::println); //Subscirbed to all items
o1.connect(); //Connect both subscribers
Using rxjava-extras:
observable
.compose(Transformers.doOnFirst(System.out::println))
It's unit tested and under the covers just uses a per-subscription counter in an operator. Note that per-subscription is important as there are plenty of uses cases where an observable instance gets used more than once and we want the doOnFirst operator to apply each time.
Source code is here.