onError java.lang.NullPointerException:尝试在空对象引用上调用虚方法'double java.lang.Double.doubleValue()'

时间:2017-04-25 10:50:53

标签: java android rx-java observable rx-android

我编写了以下代码,用于查找某些预算中的漫画 pageCount

起初我试图提出具有这样的架构的代码:

  • Stream提供 MarvelComic 对象的价格。
  • 我将来自流的 MarvelComic 对象的价格与此流中的先前漫画的价格相加并检查它是否<的 BUDGET
  • 如果是,那么我将 MarvelComic 对象的 pageCount 与来自流的下一个 MarvelComic 对象的pageCount和相加。
  • 如果是,则调用订户的 onNext

由于我无法设计一种编写代码的方法,就像我在上面的步骤中提到的那样,我采用了反应式编程的命令式编程。结果我写了下面的代码:

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");
                    }
                });

我的预订:

  1. 每次在map(), scan()内创建一个新的Hashmap是个好主意吗?
  2. 如何进一步改进此代码?
  3. 的问题:

    此代码在onError中提供 NullPointerException ,因为map.get("price")scan()中返回null。我不确定原因。

    错误:

     onError java.lang.NullPointerException: Attempt to invoke virtual method 'double java.lang.Double.doubleValue()' on a null object reference
    

    注意:

    HashMap不为null,由于某种原因,double字段将返回NULL。我正在试图弄清楚如何。

4 个答案:

答案 0 :(得分:2)

由于

,您可能会遇到一个空的初始地图
.scan(new HashMap<String, Double>(), ...)

当第一张真实地图从上游到达时,您正试图从该空白初始地图中获取值:

double sum = inputMap.get("price")+newValueMap.get("price");

我假设您希望通过使用scan来运行属性的运行聚合,因此您应该尝试scan(BiFunction)按原样发出第一个上游值,然后开始将前一个值与新值组合上游价值。

或者,您可以使用默认值预初始化new HashMap<>()并避免使用NPE:

HashMap<String, Double> initialMap = new HashMap<String, Double>();
initialMap.put("price", 0.0d);
initialMap.put("pageCount", 0.0d);
initialMap.put("comicCount", 0.0d);

Observable.fromIterable(getMarvelComicsList()).
            map(new Function<MarvelComic, HashMap<String, Double>>() {
                @Override
                public HashMap<String, Double> apply(@NonNull MarvelComic marvelComic) {
                    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(initialMap, 
            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) {
                    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;
                }
            })
            // etc.

答案 1 :(得分:1)

我尝试用不同的方法解决您的问题,这不会引发任何NPE。

请不要将HashMaps用作数据结构。发生了什么事,这是不透明的。您应该创建有意义的类。

此外,订阅者不应该做任何businesslogic。订阅者实际上应该只使用结果并执行副作用,例如更改视图。

我希望我能正确理解你的问题。

@Test
void name() {
    ArrayList<MarvelComic> marvelComics = Lists.newArrayList(new MarvelComic(10, 200), new MarvelComic(3, 133), new MarvelComic(5, 555), new MarvelComic(32, 392));

    final double BUDGET = 20.0;

    Observable<Result> resultObservable = Observable.fromIterable(marvelComics)
            .scan(Result.IDENTITY, (result, marvelComic) -> {
                double priceSum = result.sumPrice + marvelComic.getPrice();

                if (priceSum <= BUDGET) {
                    int pageCount = result.sumPageCount + marvelComic.getPageCount();
                    int comicCount = result.comicCount + 1;
                    return new Result(pageCount, priceSum, comicCount);
                }

                return Result.IDENTITY;
            })
            .skip(1) // because first Value would be Result.IDENTITY
            .takeWhile(result -> result != Result.IDENTITY);

    TestObserver<Result> test = resultObservable.test().assertValueCount(3);

    Result result1 = test.values()
            .stream()
            .reduce((result, result2) -> result2)
            .get();

    assertThat(result1.comicCount).isEqualTo(3);
    assertThat(result1.sumPageCount).isEqualTo(888);
    assertThat(result1.sumPrice).isEqualTo(18);
}

class MarvelComic {
    private final double price;
    private final int pageCount;

    MarvelComic(double price, int pageCount) {
        this.price = price;
        this.pageCount = pageCount;
    }

    public double getPrice() {
        return price;
    }

    public int getPageCount() {
        return pageCount;
    }
}

static class Result {
    private final int sumPageCount;

    private final double sumPrice;

    private final int comicCount;

    Result(int sumPageCount, double sumPrice, int comicCount) {
        this.sumPageCount = sumPageCount;
        this.sumPrice = sumPrice;
        this.comicCount = comicCount;
    }

    static Result IDENTITY = new Result(0, 0, 0);
}

答案 2 :(得分:0)

我认为您可以获得getPrice(),getPageCount()方法的空值或空值

 map.put("price", Double.valueOf(marvelComic.getPrice()));
                            map.put("pageCount", Double.valueOf(marvelComic.getPageCount()));
                            map.put("comicCount", Double.valueOf(marvelComic.getPageCount()));

或者您可以使用Double.parseDouble();方法

答案 3 :(得分:0)

你在这里使用了doubleValue()函数3次,

map.put("price", Double.valueOf(marvelComic.getPrice()));
map.put("pageCount", Double.valueOf(marvelComic.getPageCount()));
map.put("comicCount", Double.valueOf(marvelComic.getPageCount()));

确认 marvelComic 具有 价格和页数 的值, 当您将 pageCount 添加为 comicCount comicCount 地图

中的em>

我建议使用try catch并打印错误以了解根本原因