Math.floorDiv() 是 Java 8 引入的一个数学方法,用于执行向下取整的除法运算(Floor Division),其行为与标准的 / 运算符在处理负数时有显著区别。


一、方法定义

Math.floorDiv() 提供了两种重载形式:

1. floorDiv(int dividend, int divisor)

public static int floorDiv(int dividend, int divisor)
  • 参数
    • dividend:被除数
    • divisor:除数
  • 返回值
    • 返回 int 类型,表示 dividend / divisor 向负无穷方向取整的结果
  • 异常
    • ArithmeticException:当除数为 0 时抛出

2. floorDiv(long dividend, long divisor)

public static long floorDiv(long dividend, long divisor)
  • 参数
    • dividend:被除数(long 类型)
    • divisor:除数(long 类型)
  • 返回值
    • 返回 long 类型
  • 异常
    • ArithmeticException:除零异常

⚠️ 注意:没有 floatdouble 的重载版本。


二、功能说明

1. 核心概念:向下取整(Floor Division)

  • 结果是不大于代数商(dividend / divisor)的最大整数
  • 即向负无穷方向取整
  • 与标准除法 / 的区别:
    • / 是向零取整(截断小数部分)
    • floorDiv 是向负无穷取整

2. 数学定义

floorDiv(a, b) = floor(a / b)

其中 floor(x) 表示不大于 x 的最大整数

3. 与普通除法对比

被除数 除数 / 运算结果 floorDiv() 结果 说明
7 3 2 2 正数相同
-7 3 -2 -3 / 向零,floorDiv 向负无穷
7 -3 -2 -3 同上
-7 -3 2 2 负负得正,结果相同

三、示例代码

1. 基本使用对比

public class FloorDivExample {
    public static void main(String[] args) {
        // 正数除法
        System.out.println("7 / 3 = " + (7 / 3));           // 2
        System.out.println("floorDiv(7, 3) = " + Math.floorDiv(7, 3)); // 2
        
        // 负数被除数
        System.out.println("-7 / 3 = " + (-7 / 3));         // -2
        System.out.println("floorDiv(-7, 3) = " + Math.floorDiv(-7, 3)); // -3
        
        // 负数除数
        System.out.println("7 / -3 = " + (7 / -3));         // -2
        System.out.println("floorDiv(7, -3) = " + Math.floorDiv(7, -3)); // -3
        
        // 双负数
        System.out.println("-7 / -3 = " + (-7 / -3));       // 2
        System.out.println("floorDiv(-7, -3) = " + Math.floorDiv(-7, -3)); // 2
    }
}

2. 实际应用场景:时间计算

// 将秒转换为分钟和剩余秒数(正确处理负时间)
public static void convertSeconds(int totalSeconds) {
    int minutes = Math.floorDiv(totalSeconds, 60);
    int seconds = totalSeconds - minutes * 60; // 或使用 Math.floorMod()
    
    System.out.println(totalSeconds + "秒 = " + minutes + "分" + seconds + "秒");
}

// 测试
convertSeconds(125);   // 125秒 = 2分5秒
convertSeconds(-125);  // -125秒 = -3分55秒 (更符合数学直觉)

3. 与 Math.floorMod() 配合使用

// floorDiv 和 floorMod 满足: dividend = divisor * quotient + remainder
int a = -7, b = 3;
int q = Math.floorDiv(a, b);  // -3
int r = Math.floorMod(a, b);  // 2
System.out.println(a + " = " + b + " * " + q + " + " + r); // -7 = 3 * -3 + 2

四、使用技巧

1. 替代手动向下取整

// 传统方式(易出错)
int result = (int) Math.floor((double) a / b);

// 推荐方式(精确、高效)
int result = Math.floorDiv(a, b);

2. 处理负数索引

// 在循环数组中处理负索引(如日期计算)
int index = Math.floorMod(-1, 7); // 返回 6,表示上周日

3. 数学计算一致性

// 确保商和余数满足数学恒等式
// dividend = divisor * quotient + remainder
// 且 0 <= remainder < |divisor|(当 divisor > 0)

五、常见错误

错误 说明 修正
混淆 /floorDiv 误以为结果相同 理解取整方向差异
忘记处理除零异常 程序崩溃 使用 try-catch 或预先检查
期望向零取整 特别是负数场景 明确业务需求,选择合适方法
类型转换错误 long 结果赋给 int 注意返回类型

六、注意事项

  1. 除零异常:必须处理 ArithmeticException
  2. 返回类型int 版本返回 intlong 版本返回 long
  3. 性能:比普通除法稍慢,但差异通常可忽略
  4. 溢出情况
    • Math.floorDiv(Integer.MIN_VALUE, -1) 会溢出(结果超出 int 范围)
    • 实际返回 Integer.MIN_VALUE(未抛出异常,注意!
  5. Math.floorMod() 配对:设计上与 floorMod 配合使用,保持数学一致性

七、最佳实践与性能优化

实践 说明
✅ 负数除法场景使用 当需要向负无穷取整时
✅ 数学计算使用 保持与数学定义一致
✅ 时间/周期计算 如日期、星期、分页等
⚠️ 性能敏感场景评估 高频计算时测试性能影响
✅ 与 floorMod 配合 保持商余关系正确
✅ 单元测试覆盖负数 特别测试负被除数和负除数

性能对比示例:

// 测试百万次除法
// 方案1:普通除法(最快)
int result = a / b;

// 方案2:floorDiv(安全但稍慢)
result = Math.floorDiv(a, b);

// 方案3:手动 floor(最慢)
result = (int) Math.floor((double) a / b);

建议:在大多数业务场景中,性能差异可忽略,优先选择正确性和可读性。


八、总结

Math.floorDiv() 是 Java 中处理向下取整除法的标准方法,其核心优势在于:

  • 数学一致性:结果向负无穷取整,符合数学定义
  • 负数处理正确:解决了标准 / 运算符在负数场景的"截断向零"问题
  • 类型安全:避免了 Math.floor() 的浮点转换
  • 异常明确:除零时抛出清晰异常