package com.github.adamldavis; import java.io.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.Flow; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; import java.util.stream.Stream; import io.reactivex.BackpressureStrategy; import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.functions.BiConsumer; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import io.reactivex.Flowable; import io.reactivex.schedulers.Schedulers; /** * Demonstrates RxJava 2 in action. * * @author Adam L. Davis */ public class RxJavaDemo implements ReactiveStreamsDemo { public static List<Integer> doSquares() { List<Integer> squares = new ArrayList<>(); Flowable.range(1, 64) //1 .observeOn(Schedulers.computation()) //2 .map(v -> v * v) //3 .blockingSubscribe(squares::add); //4 return squares; } public static List<Integer> doParallelSquares() { List<Integer> squares = new ArrayList<>(); Flowable.range(1, 64) .flatMap(v -> //1 Flowable.just(v) .subscribeOn(Schedulers.computation()) .map(w -> w * w) ) .doOnError(ex -> ex.printStackTrace()) //2 .doOnComplete(() -> System.out.println("Completed")) //3 .blockingSubscribe(squares::add); return squares; } @Override public Future<List<Integer>> doSquaresAsync(int count) { return Flowable.range(1, count) .observeOn(Schedulers.computation()) .map(v -> v * v) .collectInto((List<Integer>) new ArrayList<Integer>(), (integers, integer) -> integers.add(integer)) .toFuture(); } @Override public Future<String> doStringConcatAsync(int count) { return Observable.range(0, count).map(i -> "i=" + i) .collectInto(new StringBuilder(), (stringBuilder, o) -> stringBuilder.append(o)) .map(StringBuilder::toString) .toFuture(); } @Override public Future<List<Integer>> doParallelSquaresAsync(int count) { return Flowable.range(1, count) .flatMap(v -> Flowable.just(v) .subscribeOn(Schedulers.computation()) .map(w -> w * w) ).collectInto((List<Integer>) new ArrayList<Integer>(), (integers, integer) -> integers.add(integer)) .toFuture(); } @Override public Future<String> doParallelStringConcatAsync(int count) { BiConsumer<StringBuilder, Object> collector = (stringBuilder, o) -> stringBuilder.append(o); //1 return Observable.range(0, count).map(i -> "i=" + i) .window(10) // 3 .flatMap(flow -> flow.subscribeOn(Schedulers.computation()) .collectInto(new StringBuilder(), collector).toObservable()) .collectInto(new StringBuilder(), collector) //4 .map(StringBuilder::toString) //5 .toFuture(); } public static void runComputation() { Flowable<String> source = Flowable.fromCallable(() -> { //1 Thread.sleep(1000); // imitate expensive computation return "Done"; }); source.doOnComplete(() -> System.out.println("Completed runComputation")); Flowable<String> background = source.subscribeOn(Schedulers.io()); //2 Flowable<String> foreground = background.observeOn(Schedulers.single());//3 foreground.subscribe(System.out::println, Throwable::printStackTrace);//4 } public static void writeFile(File file) { try (PrintWriter pw = new PrintWriter(file)) { Flowable.range(1, 100) .observeOn(Schedulers.newThread()) .blockingSubscribe(pw::println); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static void readFile(File file) { try (final BufferedReader br = new BufferedReader(new FileReader(file))) { Flowable<String> flow = Flowable.fromPublisher(new FilePublisher(br)); flow.observeOn(Schedulers.io()) .blockingSubscribe(System.out::println); } catch (IOException e) { e.printStackTrace(); } } public static void readFile2(File file) { Single<BufferedReader> readerSingle = Single.just(file) //1 .observeOn(Schedulers.io()) //2 .map(FileReader::new) .map(BufferedReader::new); //3 Flowable<String> flowable = readerSingle.flatMapPublisher(reader -> //4 Flowable.fromIterable( //5 () -> Stream.generate(readLineSupplier(reader)).iterator() ).takeWhile(line -> !"EOF".equals(line))); //6 flowable .doOnNext(it -> System.out.println("thread=" + Thread.currentThread().getName())) //7 .doOnError(ex -> ex.printStackTrace()) .blockingSubscribe(System.out::println); //8 } private static Supplier<String> readLineSupplier(BufferedReader reader) { return () -> { try { String line = reader.readLine(); return line == null ? "EOF" : line; } catch (IOException ex) { throw new RuntimeException(ex); }}; } public static int countUsingBackpressure(long sleepMillis) throws InterruptedException { AtomicInteger count = new AtomicInteger(0); //1 Flowable<Long> interval = Observable.interval(1, TimeUnit.MILLISECONDS) //2 .toFlowable(BackpressureStrategy.LATEST) //3 .take(2000); //4 interval.subscribe(x -> { Thread.sleep(100); //5 count.incrementAndGet(); }); Thread.sleep(sleepMillis); //6 return count.get(); } static class FilePublisher implements Publisher<String> { BufferedReader reader; public FilePublisher(BufferedReader reader) { this.reader = reader; } @Override public void subscribe(Subscriber<? super String> subscriber) { subscriber.onSubscribe( new FilePublisherSubscription(this, subscriber)); } public String readLine() throws IOException { return reader.readLine(); } } static class FilePublisherSubscription implements Subscription { FilePublisher publisher; Subscriber<? super String> subscriber; public FilePublisherSubscription( FilePublisher publisher, Subscriber<? super String> subscriber) { this.publisher = publisher; this.subscriber = subscriber; } @Override public void request(long n) { try { String line; for (int i = 0; i < n && publisher != null && (line = publisher.readLine()) != null; i++) { if (subscriber != null) subscriber.onNext(line); } } catch (IOException ex) { subscriber.onError(ex); } subscriber.onComplete(); } @Override public void cancel() { publisher = null; } } }