计算Java 8流中可能包含无效数字的映射值的总和

时间:2017-08-25 01:03:09

标签: java java-8

我有一张地图:Map<String, Map<String, String>> x

我想计算第二张地图中的值总和:

x.values().stream().mapToDouble(y -> Double.parse(y.get("myKey"))).sum();

但是如果y.get(“myKey”)不是有效数字,它将按预期抛出错误...有没有办法可以避免它并只传递有效数字

我看到来自guava库的Doubles.tryParse会返回null,因为它不可解析。但我无法弄清楚如何使用它来只加总有效数字。

3 个答案:

答案 0 :(得分:5)

无需使用第三方库,只需抓住NumberFormatException

即可
double sum = x.values().stream().mapToDouble(y -> {
    try {
        return Double.parseDouble(y.get("myKey"));
    } catch (NumberFormatException e) {
        return 0.0;
    }
}).sum();

如果忽略缺少值,您也可以抓住RuntimeException,而不是导致NullPointerException

答案 1 :(得分:4)

Doubles.tryParse()如果失败则返回null。以下是您如何利用这一优势:

x.values()
    .stream()
    .map(y -> Doubles.tryParse(y.get("myKey")))
    .filter(Objects::nonNull)  // exclude invalid numbers
    .mapToDouble(Double::doubleValue)
    .sum();

答案 2 :(得分:2)

这些通过使用RegEx进行预过滤来避免引发/捕获异常(我可能会对此进行此操作,但在反射 我不确定这对双打是否合理 由于格式复杂性。)

不介意提出异常?见:#45873009
使用番石榴了吗?请参阅:#45873075

1。 filter()String然后map()

x.values()
    .stream()
    .map(m -> m.get("myKey"))
    .filter(s -> s.matches(Numbers.DOUBLE_FORMAT)) // you'll want a constant...
    .mapToDouble(Double::parseDouble)
    .sum();

2。效用和默认值

x.values()
    .stream()
    .map(m -> m.get("myKey"))
    .mapToDouble(Numbers::parseDoubleOrDefault) // default 0.0 doesn't affect sum...
    .sum();

3。 Utility和flatMap()

x.values()
    .stream()
    .map(m -> m.get("myKey"))
    .flatMapToDouble(Numbers::tryParseDouble)
    .sum();

...这里是实用程序类

public class Numbers {

    // Extensive regex! Thank you @Andreas & Oracle Docs
    // https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#valueOf-java.lang.String-
    private static final String DIGITS = "(\\p{Digit}+)";
    private static final String HEX_DIGITS = "(\\p{XDigit}+)";
    private static final String EXPONENT = "[eE][+-]?"+ DIGITS;
    public static final String DOUBLE_FORMAT = "[\\x00-\\x20]*[+-]?(NaN|Infinity|((("+ DIGITS +"(\\.)?("+ DIGITS +"?)("+ EXPONENT +")?)|(\\.("+ DIGITS +")("+ EXPONENT +")?)|(((0[xX]" + HEX_DIGITS + "(\\.)?)|(0[xX]" + HEX_DIGITS + "?(\\.)" + HEX_DIGITS + "))[pP][+-]?" + DIGITS + "))[fFdD]?))[\\x00-\\x20]*";

    public double parseDoubleOrDefault(final String input, final double defaultValue) {
        return input.matches(DOUBLE_FORMAT)
            ? Double.parseDouble(input)
            : defaultValue;
    }

    public double parseDoubleOrDefault(final String input) {
        return parseDoubleOrDefault(0.0);
    }

    // Stream because Java 8 flatMap doesn't work on Optional
    public DoubleStream tryParseDouble(final String input) {
        return input.matches(DOUBLE_FORMAT)
            ? DoubleStream.of(Double.parseDouble(input))
            : DoubleStream.empty();
    }

}