I have written the following code for finding pageCount of comics that lie within certain budget.
At first I tried to come up with code that would have architecture like this:
- Stream gives price of a MarvelComic object.
- I sum the price of the MarvelComic object from stream with prices of the previous comics that came down this stream and check if it's < BUDGET
- If Yes, then I sum the pageCount of the MarvelComic object with the pageCount sum of previous MarvelComic objects that came down the stream.
- If yes, then onNext of the subscriber is called.
Since I couldn't devise a way to write code like I mentioned in the steps above, I resorted to mashing imperative programming with Reactive Programming. As a result I wrote the following code:
Observable.fromIterable(getMarvelComicsList()).
                map(new Function<MarvelComic, HashMap<String, Double>>() {
                    @Override
                    public HashMap<String, Double> apply(@NonNull MarvelComic marvelComic) throws Exception {
                        HashMap<String, Double> map = new HashMap<String, Double>();
                        map.put("price", Double.valueOf(marvelComic.getPrice()));
                        map.put("pageCount", Double.valueOf(marvelComic.getPageCount()));
                        map.put("comicCount", Double.valueOf(marvelComic.getPageCount()));
                        return map;
                    }
                })
                .scan(new HashMap<String, Double>(), new BiFunction<HashMap<String, Double>, HashMap<String, Double>, HashMap<String, Double>>() {
                    @Override
                    public HashMap<String, Double> apply(@NonNull HashMap<String, Double> inputMap, @NonNull HashMap<String, Double> newValueMap) throws Exception {
                        double sum = inputMap.get("price")+newValueMap.get("price");
                        double count = inputMap.get("pageCount")+newValueMap.get("pageCount");
                        double comicCount = inputMap.get("comicCount")+newValueMap.get("comicCount");
                        HashMap<String, Double> map = new HashMap<String, Double>();
                        map.put("price", sum);
                        map.put("pageCount", count);
                        map.put("comicCount", comicCount);
                        return map;
                    }
                })
                .takeWhile(new Predicate<HashMap<String, Double>>() {
                    @Override
                    public boolean test(@NonNull HashMap<String, Double> stringDoubleHashMap) throws Exception {
                        return stringDoubleHashMap.get("price") < budget;
                    }
                })
                .subscribe(new DisposableObserver<HashMap<String, Double>>() {
                    @Override
                    public void onNext(HashMap<String, Double> stringDoubleHashMap) {
                        double sum = stringDoubleHashMap.get("price");
                        double pageCount = stringDoubleHashMap.get("pageCount");
                        double comicCount = stringDoubleHashMap.get("comicCount");
                        Timber.e("sum %s  pageCount %s  ComicCount: %s", sum, pageCount, comicCount);
                    }
                    @Override
                    public void onError(Throwable e) {
                        Timber.e("onError %s", e.fillInStackTrace());
                    }
                    @Override
                    public void onComplete() {
                        Timber.e("onComplete");
                    }
                });
My Reservations:
- Is it good idea to create a new Hashmap every time inside map(), scan()?
- How can I improve this code further?
Issues:
This code gives NullPointerException in onError because map.get("price") returns null in scan(). I'm not really sure of the reason.
Error:
 onError java.lang.NullPointerException: Attempt to invoke virtual method 'double java.lang.Double.doubleValue()' on a null object reference
NOTE:
HashMap isn't null, the double field is being returned as NULL for some reason. I'm trying to figure out how.
 
     
     
     
    