From RxJava 1 to RxJava 2 - java

I'm trying to convert this RxJava1 code to RxJava2
public static Observable<Path> listFolder(Path dir, String glob) {
return Observable.<Path>create(subscriber -> {
try {
DirectoryStream<Path> stream =
Files.newDirectoryStream(dir, glob);
subscriber.add(Subscriptions.create(() -> {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}));
Observable.<Path>from(stream).subscribe(subscriber);
} catch (DirectoryIteratorException ex) {
subscriber.onError(ex);
} catch (IOException ioe) {
subscriber.onError(ioe);
}
});
}
The thing is that in Rxjava2 I don't get a subscriber to add a new subscription to it.

Enjoy RxJava 2 conciseness (Flowable is the backpressure supporting class now):
public static Flowable<Path> listFolder(Path dir, String glob) {
return Flowable.using(
() -> Files.newDirectoryStream(dir, glob),
stream -> Flowable.fromIterable(stream),
stream -> stream.close());
}
If you don't want backpressure then replace Flowable with Observable.

Related

How can I asynchronously emit to as Sink?

I have following proactive method.
void acceptSome(Consumer<? super String> consumer) {
consumer.accept("A");
consumer.accept("B");
}
And I wrote following method for reactor.
void emitAll(Sinks.Many<String> sink) {
try {
acceptSome(e -> {
sink.emitNext...(e);
});
sink.emitComplete...
} catch (Exception e) {
sink.emitError...
}
}
And I tested with following two methods, one with full buffer and the other with single buffer using thread.
#Test
void emitAll__onBackpressureBufferAll() {
final var sink = Sinks.many().unicast().<String>onBackpressureBuffer();
TheClass.emitAll(sink);
sink.asFlux()
.doOnNext(e -> {
log.debug("next: {}", e);
})
.blockLast();
}
#Test
void emitAll__onBackpressureBufferOne() {
var sink = Sinks.many().unicast().<String>onBackpressureBuffer(new ArrayBlockingQueue<>(1));
new Thread(() -> {
sink.asFlux()
.doOnNext(e -> {
log.debug("next: {}", e);
})
.blockLast();
}).start();
TheClass.emitAll(sink);
}
Now, How can I (Can I do that?) implement a method accepts a sink and returns a Flux or CompletableFuture<Flux> so that caller simply subscribe to the result without thread, with minimum buffer?
CompletableFuture<Flux<String>> emitAllAsync(Sinks.Many<String> sink) {
}
Thank you.
I tried some and it works yet doesn't seem righteous.
void emitAll(Sinks.Many<String> sink, Semaphore semaphore) {
try {
acceptSome(v -> {
try {
semaphore.acquire();
} catch (final InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
log.debug("emitting {}", v);
sink.tryEmitNext(v).orThrow();
});
sink.tryEmitComplete().orThrow();
} catch (final IOException ioe) {
log.error("failed to emit to {}", sink, ioe);
sink.tryEmitError(ioe).orThrow();
}
}
CompletableFuture<Flux<String>> emitAllAsync() {
var sink = Sinks.many().unicast().<String>onBackpressureBuffer(new ArrayBlockingQueue<>(1));
var semaphore = new Semaphore(1);
CompletableFuture
.runAsync(() -> emitAll(sink, semaphore));
return CompletableFuture.completedFuture(sink.asFlux().doOnNext(v -> semaphore.release()));
}

Use try-with-resources or close this "Stream" in a "finally" clause

I am having trouble to apply the suggested method by Sonarqube scan in this line of code/method.
Sonarqube says, "Use try-with-resources or close this "Stream" in a "finally" clause."
Files.list(voucherDirectory)
#Override
public String getLastModifiedFile() {
Path voucherDirectory = Paths.get(vouchiDir);
Optional<Path> lastFilePath = Optional.empty();
try {
lastFilePath = Files.list(voucherDirectory)
.filter(f -> !Files.isDirectory(f))
.max(Comparator.comparingLong(f -> f.toFile()
.lastModified()));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
if (lastFilePath.isPresent()) {
return lastFilePath.get().getFileName().toString();
}
return "none";
}
Any help is really appreciated!
You need to do this:
try (Stream<Path> list = Files.list(voucherDirectory)) {
lastFilePath = list
.filter(f -> !Files.isDirectory(f))
.max(Comparator.comparingLong(f -> f.toFile()
.lastModified()));
} catch (IOException e) {
log.error(e.getMessage(), e);
}

Asynchronous forEach over an array with RxJava

I am trying to iterate over an array of Maps and do some asynchronous actions. I have tried a few things using the RxJava library, but everything I've tried seems to be synchronous. I am trying to avoid creating new threads manually and want to let RxJava handle it. This is what I've tried so far.
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.computation())
.forEach(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.computation())
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
When I run unit tests with the code above I see the following output.
1
2
1
2
1
2
...
What I want to see is
1
1
1
...
2
2
2
How do I iterate asynchronously over a Map array using RxJava?
You can achieve it changing from Observable to Flowable and use parallel:
Flowable.fromIterable(array)
.parallel(3) // number of items in parallel
.runOn(Schedulers.newThread()) // the desired scheduler
.map(item -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
return Completable.complete();
})
.sequential().subscribe();
If you're stuck using RxJava 1.x then you wont have access to the Flowable class. This wasn't my case, but something like the below code can do parallel actions. There is more nesting, but it works.
final ExecutorService executor = Executors.newFixedThreadPool(2);
List<String> iterableList = new ArrayList<>();
iterableList.add("one");
iterableList.add("two");
iterableList.add("three");
iterableList.add("4");
iterableList.add("5");
iterableList.add("6");
iterableList.add("7");
iterableList.add("8");
iterableList.add("9");
Observable.from(iterableList)
.flatMap(val -> Observable.just(val)
.subscribeOn(Schedulers.from(executor))
.doOnNext(numString -> {
try {
System.out.println(1);
Thread.sleep(500);
System.out.println(2);
} catch (Exception ex) {
}
})
)
.subscribe();

How to regroup catch finally into one method in java 8?

New to java 8, I would like to optimise my code bellow:
public Response create() {
try{
...
} catch (Exception e) {
codeA;
} finally {
codeB;
}
}
public Response update() {
try{
...
} catch (Exception e) {
codeA;
} finally {
codeB;
}
}
I have a lot of methods using this same way to catch exceptions and do the same finally, is that possible to replace the bellow common code by a method in java 8? So that I could optimise all my methods who use this common code.
} catch (Exception e) {
codeA;
} finally {
codeB;
}
Depends what you do in the .... You could do something like this:
private Response method(Supplier<Response> supplier) {
try{
return supplier.get();
} catch (Exception e) {
codeA;
} finally {
codeB;
}
}
and invoke like:
public Response create() { return method(() -> { ... for create }); }
public Response update() { return method(() -> { ... for update }); }
You could wrap your payload and put it to the separate method. One thing; what do you expect to return on exception catch. This time this is null, but probably you could provide default value.
public static <T> T execute(Supplier<T> payload) {
try {
return payload.get();
} catch(Exception e) {
// code A
return null;
} finally {
// code B
}
}
Client code could look like this:
public Response create() {
return execute(() -> new CreateResponse());
}
public Response update() {
return execute(() -> new UpdateResponse());
}
This could be a generic solution.
//here describe supplier which can throw exceptions
#FunctionalInterface
public interface ThrowingSupplier<T> {
T get() throws Exception;
}
// The wrapper
private <T> T callMethod(ThrowingSupplier<T> supplier) {
try {
return supplier.get();
} catch (Exception e) {
//code A
}finally {
// code B
}
}

Spring Reactor Merge vs Concat

I´m playing with Spring reactor, and I cannot see any differences between concat and merge operator
Here's my example
#Test
public void merge() {
Flux<String> flux1 = Flux.just("hello").doOnNext(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Flux<String> flux2 = Flux.just("reactive").doOnNext(value -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Flux<String> flux3 = Flux.just("world");
Flux.merge(flux1, flux2, flux3)
.map(String::toUpperCase)
.subscribe(System.out::println);
}
#Test
public void concat() {
Flux<String> flux1 = Flux.just("hello").doOnNext(value -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Flux<String> flux2 = Flux.just("reactive").doOnNext(value -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Flux<String> flux3 = Flux.just("world");
Flux.concat(flux1, flux2, flux3)
.map(String::toUpperCase)
.subscribe(System.out::println);
}
Both behave exactly the same. Can someone explain the difference between the two operations?
The essential difference between merge and concat is that in merge, both streams are live. In case of concat, first stream is terminated and then the other stream is concatenated to it.
Concat
Merge
The difference is already mentioned in the API docs that while concat first reads one flux completely and then appends the second flux to that, merge operator doesn't guarantee the sequence between the two flux.
In order to see the difference, modify your merge() code as below.
e.g. sample code below
//Flux with Delay
#Test
public void merge() {
Flux<String> flux1 = Flux.just("Hello", "Vikram");
flux1 = Flux.interval(Duration.ofMillis(3000))
.zipWith(flux1, (i, msg) -> msg);
Flux<String> flux2 = Flux.just("reactive");
flux2 = Flux.interval(Duration.ofMillis(2000))
.zipWith(flux2, (i, msg) -> msg);
Flux<String> flux3 = Flux.just("world");
Flux.merge(flux1, flux2, flux3)
.subscribe(System.out::println);
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As you modify the Flux.interval duration, currently set as 3000 milliseconds you will see that the output with merge() keeps changing. But with concat(), the output will be always same.
Another noteworthy difference is that all variations of concat subscribe to the second stream lazily, only after the first stream has terminated.
Whereas all variations of merge subscribe to the publishers eagerly (all publishers are subscribed together)
Running the below code highlights this aspect:
//Lazy subscription of conact
Flux.concat(Flux.just(1, 2, 3, 4).delayElements(Duration.ofMillis(500)),
Flux.just(10, 20, 30, 40).delayElements(Duration.ofMillis(500)))
.subscribe(System.out::println, System.out::println);
//Eager subscription of the merge. Also, try mergeSequential.
Flux.merge(Flux.range(500, 3).delayElements(Duration.ofMillis(500)),
Flux.range(-500, 3).delayElements(Duration.ofMillis(300)))
.subscribe(System.out::println, System.out::println);

Categories

Resources