ZetCode

Java LongBinaryOperator 接口

最后修改时间:2025 年 4 月 16 日

java.util.function.LongBinaryOperator 接口表示对两个 long 值的操作,产生一个 long 结果。它是一个函数式接口,只有一个抽象方法 applyAsLong。此接口专门用于原始 long 类型,以避免装箱开销。

LongBinaryOperator 是 Java 8 中添加的 Java 函数式编程实用程序的一部分。它对于数学运算和规约(reduction)非常有用,在原始类型上进行性能优化时很重要。该接口没有默认方法或静态方法。

LongBinaryOperator 接口概述

LongBinaryOperator 接口包含一个必须实现的方法。该方法接受两个 long 参数并返回一个 long 值。这使其成为对原始 long 类型进行算术运算的理想选择。

@FunctionalInterface
public interface LongBinaryOperator {
    long applyAsLong(long left, long right);
}

上面的代码显示了 LongBinaryOperator 的简单结构。它使用 @FunctionalInterface 注解来指示其单一抽象方法。该接口通过使用原始类型来避免对象创建开销。

LongBinaryOperator 的基本用法

使用 LongBinaryOperator 的最简单方法是使用 lambda 表达式。我们定义如何将两个 long 值组合成一个结果。该示例显示了基本的算术运算。

Main.java
package com.zetcode;

import java.util.function.LongBinaryOperator;

public class Main {

    public static void main(String[] args) {

        // Define addition operator
        LongBinaryOperator add = (a, b) -> a + b;
        
        // Define multiplication operator
        LongBinaryOperator multiply = (a, b) -> a * b;
        
        System.out.println("10 + 20 = " + add.applyAsLong(10, 20));
        System.out.println("5 * 7 = " + multiply.applyAsLong(5, 7));
        
        // Using method reference for max operation
        LongBinaryOperator max = Math::max;
        System.out.println("Max of 15 and 25: " + max.applyAsLong(15, 25));
    }
}

此示例演示了使用 lambda 表达式的基本 LongBinaryOperator 用法。我们创建了加法和乘法的运算符。方法引用展示了如何使用与接口兼容的现有方法。打印结果。

使用 LongBinaryOperator 进行 reduce 操作

LongBinaryOperator 常用在原始 long 类型的流上的 reduce 操作中。这允许有效的聚合,而无需装箱开销。该示例对 LongStream 中的数字求和。

Main.java
package com.zetcode;

import java.util.stream.LongStream;
import java.util.function.LongBinaryOperator;

public class Main {

    public static void main(String[] args) {

        LongStream numbers = LongStream.of(1, 2, 3, 4, 5);
        
        // Sum reduction using LongBinaryOperator
        long sum = numbers.reduce(0, (a, b) -> a + b);
        System.out.println("Sum: " + sum);
        
        // Alternative with method reference
        LongStream numbers2 = LongStream.of(10, 20, 30);
        long sum2 = numbers2.reduce(0, Long::sum);
        System.out.println("Sum2: " + sum2);
        
        // Product reduction
        LongStream factors = LongStream.of(2, 3, 4);
        long product = factors.reduce(1, (a, b) -> a * b);
        System.out.println("Product: " + product);
    }
}

此示例展示了 LongBinaryOperator 在流规约中的应用。我们使用 lambda 表达式和方法引用对数字求和。乘积计算演示了另一种常见的规约模式。所有操作都直接使用原始 long 类型。

自定义数学运算

我们可以使用 LongBinaryOperator 实现自定义数学运算。当标准运算符无法满足需求时,这非常有用。该示例展示了幂运算和最大公约数 (GCD) 的计算。

Main.java
package com.zetcode;

import java.util.function.LongBinaryOperator;

public class Main {

    public static void main(String[] args) {

        // Power operation
        LongBinaryOperator power = (base, exponent) -> {
            long result = 1;
            for (long i = 0; i < exponent; i++) {
                result *= base;
            }
            return result;
        };
        
        System.out.println("2^5 = " + power.applyAsLong(2, 5));
        
        // GCD operation using Euclidean algorithm
        LongBinaryOperator gcd = (a, b) -> {
            while (b != 0) {
                long temp = b;
                b = a % b;
                a = temp;
            }
            return a;
        };
        
        System.out.println("GCD of 56 and 42: " + gcd.applyAsLong(56, 42));
    }
}

此示例实现了自定义数学运算。幂运算符通过迭代计算指数。GCD 运算符使用欧几里德算法。两者都展示了如何封装复杂的运算。

与其他函数式接口组合

LongBinaryOperator 可以与其他函数式接口结合使用,以获得更复杂的行为。该示例展示了在操作之前进行过滤以及链式操作。

Main.java
package com.zetcode;

import java.util.function.LongBinaryOperator;
import java.util.function.LongPredicate;

public class Main {

    public static void main(String[] args) {

        // Only operate if both numbers are even
        LongBinaryOperator conditionalAdd = (a, b) -> {
            LongPredicate isEven = n -> n % 2 == 0;
            return isEven.test(a) && isEven.test(b) ? a + b : 0;
        };
        
        System.out.println("Conditional add (4,6): " + 
            conditionalAdd.applyAsLong(4, 6));
        System.out.println("Conditional add (3,8): " + 
            conditionalAdd.applyAsLong(3, 8));
            
        // Chaining operations
        LongBinaryOperator addThenDouble = (a, b) -> (a + b) * 2;
        System.out.println("Add then double (3,4): " + 
            addThenDouble.applyAsLong(3, 4));
    }
}

此示例将 LongBinaryOperator 与 LongPredicate 结合用于条件操作。我们还展示了如何在单个 lambda 中链接操作。这展示了 Java 中函数组合的灵活性。

在并行流中使用

LongBinaryOperator 在并行流中特别有用,其中操作必须是可结合的,才能获得正确的结果。该示例展示了使用自定义运算符的并行规约。

Main.java
package com.zetcode;

import java.util.stream.LongStream;
import java.util.function.LongBinaryOperator;

public class Main {

    public static void main(String[] args) {

        // Custom associative operation (a + b)^2
        LongBinaryOperator sumOfSquares = (a, b) -> (a + b) * (a + b);
        
        long result = LongStream.rangeClosed(1, 10)
            .parallel()
            .reduce(0, sumOfSquares);
            
        System.out.println("Parallel reduction result: " + result);
        
        // Verification with sequential stream
        long seqResult = LongStream.rangeClosed(1, 10)
            .reduce(0, sumOfSquares);
            
        System.out.println("Sequential result: " + seqResult);
    }
}

此示例演示了使用自定义可结合操作的并行流规约。运算符必须是可结合的才能在并行中正确工作。我们验证了并行和顺序执行的结果匹配。

性能比较

与基于对象的替代方案相比,使用 LongBinaryOperator 处理原始 long 类型可以提供显著的性能优势。该示例比较了原始类型和基于对象的规约。

Main.java
package com.zetcode;

import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.function.LongBinaryOperator;
import java.util.function.BinaryOperator;

public class Main {

    public static void main(String[] args) {

        final int SIZE = 10_000_000;
        
        // Primitive long stream with LongBinaryOperator
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(1, SIZE)
            .reduce(0, (a, b) -> a + b);
        long primitiveTime = System.currentTimeMillis() - start;
        
        // Object stream with BinaryOperator
        start = System.currentTimeMillis();
        Long sumObj = Stream.iterate(1L, n -> n + 1)
            .limit(SIZE)
            .reduce(0L, (a, b) -> a + b);
        long objectTime = System.currentTimeMillis() - start;
        
        System.out.println("Primitive sum: " + sum + " in " + 
            primitiveTime + "ms");
        System.out.println("Object sum: " + sumObj + " in " + 
            objectTime + "ms");
    }
}

此示例比较了原始 long 操作和装箱 Long 操作之间的性能。使用 LongBinaryOperator 的原始类型版本通常更快,因为它避免了装箱开销。打印结果和时间。

来源

Java LongBinaryOperator 接口文档

在本文中,我们涵盖了 Java LongBinaryOperator 接口的基本使用模式。理解这些概念对于在现代 Java 应用程序中进行高效的数值处理至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在这一领域拥有多年的经验。我从 2007 年开始撰写编程文章,此后撰写了 1400 多篇文章和 8 本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程