转换为函数 Java 样式

Converting to functional Java style

如何使用过滤器、收集器等以适当的 Java 8 种功能样式重写以下内容:

private BigInteger calculateProduct(char[] letters) {

    int OFFSET = 65;

    BigInteger[] bigPrimes = Arrays.stream(
            new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
            37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
            97, 101, 103, 107, 109, 113 })
            .mapToObj(BigInteger::valueOf)
            .toArray(BigInteger[]::new);


    BigInteger result = BigInteger.ONE;
    for (char c : letters) {
        //System.out.println(c+"="+(int)c);
        if (c < OFFSET) {
            return new BigInteger("-1");
        }
        int pos = c - OFFSET;
        result = result.multiply(bigPrimes[pos]);
    }
    return result;
}


@Test public void test() {
    assertThat(calculateProduct(capitalize("carthorse"))).isEqualTo(calculateProduct(capitalize("orchestra")));

}


private char[] capitalize(String word) {
    return word.toUpperCase().toCharArray();
}

我不知道你为什么想要那个,但可能是这个(它创建了更多的对象并且更冗长):

private static BigInteger calculateProduct(char[] letters) {

    int OFFSET = 65;

    BigInteger[] bigPrimes = Arrays.stream(
            new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
                    37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
                    97, 101, 103, 107, 109, 113 })
            .mapToObj(BigInteger::valueOf)
            .toArray(BigInteger[]::new);

    Optional<Character> one = IntStream.range(0, letters.length)
            .mapToObj(x -> letters[x])
            .filter(x -> x < OFFSET)
            .findAny();

    if (one.isPresent()) {
        return new BigInteger("-1");
    } else {
        return IntStream.range(0, letters.length)
                .mapToObj(x -> letters[x])
                .parallel()
                .reduce(
                        BigInteger.ONE,
                        (x, y) -> {
                            int pos = y - OFFSET;
                            return x.multiply(bigPrimes[pos]);
                        },
                        BigInteger::multiply);
    }

}

你可以这样做:

static final BigInteger[] PRIMES
    = IntStream.of(
        2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
        59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113)
    .mapToObj(BigInteger::valueOf)
    .toArray(BigInteger[]::new);

private BigInteger calculateProduct(char[] letters) {
    final int OFFSET = 65;
    final CharBuffer cb = CharBuffer.wrap(letters);
    if(cb.chars().anyMatch(c -> c<OFFSET))
        return BigInteger.ONE.negate();
    return cb.chars()
        .mapToObj(c -> PRIMES[c-OFFSET])
        .reduce(BigInteger.ONE, BigInteger::multiply);
}

请注意,将 PRIMES 数组的创建移出方法,以避免为每次调用再次生成它,这是一项独立于您使用循环还是“函数式”操作的改进。

此外,您的代码无法处理过大的字符,因此您可以将方法改进为

private BigInteger calculateProduct(char[] letters) {
    final int OFFSET = 65;
    final CharBuffer cb = CharBuffer.wrap(letters);
    if(cb.chars().mapToObj(c -> c-OFFSET).anyMatch(c -> c<0||c>PRIMES.length))
        return BigInteger.ONE.negate();
    return cb.chars()
        .mapToObj(c -> PRIMES[c-OFFSET])
        .reduce(BigInteger.ONE, BigInteger::multiply);
}