HOWTO · Java

Java 中除以零异常

本文说明 Java 整数除以零为何会抛出 ArithmeticException,以及浮点数除以带符号的零时,非零分子会得到带符号的 Infinity,而零除以零会得到 NaN,并介绍如何安全处理这两种情况。

本页内容

Java 对整数和浮点数除以零的处理方式不同。整数除法会抛出 ArithmeticException;浮点除法遵循 IEEE 754,非零分子除以带符号的零会得到带符号的 Infinity,而零除以零会得到 NaN。执行整数除法前应先检查分母;对于浮点数零,则应根据应用需求决定是拒绝输入,还是处理由此产生的特殊值。

Java 中整数除以零

对于 int 和 long 等整数类型,除以零会抛出 ArithmeticException。整数除数为零时,取余运算符也会抛出相同异常。如果异常未被捕获,当前执行路径会在除法之后的语句运行前停止。

下面是一个完整程序,用两个整数输入计算商。

public class Main {
  public static void main(String[] args) {
    int numerator = 10;
    int denominator = 2;
    int quotient = numerator / denominator;
    System.out.println("Quotient: " + quotient);
  }
}

结果是整数,因此 10 / 2 得到 5。如果将 denominator 改为 0,除法就会抛出 ArithmeticException,后续的打印语句不会执行。示例输出中的标签(例如 “Quotient”)保留为英文。确切的堆栈跟踪还包含源代码位置等细节,这些内容取决于程序的编译和运行方式。

使用条件判断避免整数除以零

如果任务不允许除数为零,应在执行运算前检查分母,并选择符合应用需求的处理方式。下面的示例使用固定值,因此可以作为单个文件编译和运行;在实际应用中,请将这些值替换为经过验证的输入。

public class Main {
  public static void main(String[] args) {
    int numerator = 10;
    int denominator = 0;

    if (denominator == 0) {
      System.out.println("Cannot calculate a quotient: denominator is zero.");
    } else {
      int quotient = numerator / denominator;
      System.out.println("Quotient: " + quotient);
    }
  }
}

只有在分母非零的分支中才会执行除法。处理用户输入时,还应单独验证解析过程,并按照程序的交互方式报告问题,例如提示用户重新输入,或在用户界面中显示验证消息。

使用 try-catch 处理整数除以零

如果整数除法属于一个可能失败、且调用方有明确恢复方式的较大操作,try-catch 就很有用。如果能在操作附近捕获 ArithmeticException 并作出有用响应,可以采用这种方式;如果零是预期会遇到的输入情况,通常直接进行条件检查会更清晰。

public class Main {
  public static void main(String[] args) {
    int numerator = 10;
    int denominator = 0;

    try {
      int quotient = numerator / denominator;
      System.out.println("Quotient: " + quotient);
    } catch (ArithmeticException error) {
      System.out.println("Cannot calculate a quotient: denominator is zero.");
    }
  }
}

这种方式会捕获整数除法错误,并让程序在 catch 块之后继续运行。它是在尝试运算后处理失败,并不会使除以零变成有效操作。避免使用过于宽泛的捕获,以免掩盖其他编程错误。

使用三元运算符处理整数除以零

三元表达式可以将简短的选择逻辑放在计算附近。应明确说明备用值的含义:在特定业务领域中返回 0 可能合适,但也可能被误认为是真实的商。如果调用方必须区分运算失败与数值结果,请使用能表达更多信息的结果类型,或单独使用条件语句。

public class Main {
  public static void main(String[] args) {
    int numerator = 10;
    int denominator = 0;

    String result = denominator == 0
        ? "No quotient: denominator is zero."
        : Integer.toString(numerator / denominator);
    System.out.println(result);
  }
}

Java 只会计算被选中的分支,因此分母为零时会跳过除法。此示例使用消息而不是数值默认值,以明确区分两种结果。

Java 中浮点数除以零

Java 的 float 和 double 除法遵循 IEEE 754。非零值除以正零或负零会得到带符号的 Infinity;符号取决于两个操作数。零除以零会得到 NaN(非数值)。这些运算本身不会抛出 ArithmeticException。

public class Main {
  public static void main(String[] args) {
    double positiveInfinity = 1.0 / 0.0;
    double negativeInfinity = 1.0 / -0.0;
    double notANumber = 0.0 / 0.0;

    System.out.println("Positive divisor sign: " + positiveInfinity);
    System.out.println("Negative divisor sign: " + negativeInfinity);
    System.out.println("Zero divided by zero: " + notANumber);
  }
}

Infinity 和 NaN 是含义不同的两种值。后续计算若涉及它们,也可能产生非有限结果。如果应用要求数值必须有限,请使用 Double.isFinite(value) 或对应的 Float.isFinite(value) 进行检查;像 value == Double.NaN 这样的比较无法检测 NaN。

使用条件判断检查浮点数分母

如果应用规定带符号的零都不能作为分母,请在除法前将数值与 0.0 比较。Java 在此比较中会将正零和负零视为相等。精确的零值检查无法解决所有接近零时的数值稳定性问题;可接受的范围取决于数据的尺度和含义。

public class Main {
  public static void main(String[] args) {
    double numerator = 10.0;
    double denominator = 0.0;

    if (denominator == 0.0) {
      System.out.println("Cannot calculate a quotient: denominator is zero.");
    } else {
      double quotient = numerator / denominator;
      System.out.println("Quotient: " + quotient);
    }
  }
}

只有当业务领域确实需要时才使用容差,并根据数值的大小和单位来选择。完成除法后,如果下游处理不接受 Infinity 或 NaN,请使用 Double.isFinite 验证结果。

为浮点数零抛出并捕获应用自定义异常

浮点数除以零不会抛出 ArithmeticException,因此仅在除法外包一层 try-catch 并不能拒绝零分母。如果 API 将这种情况视为错误,请先显式检查,再在除法前抛出应用自定义异常。示例使用 IllegalArgumentException,因为传入的参数不在该方法接受的范围内。

public class Main {
  static double divide(double numerator, double denominator) {
    if (denominator == 0.0) {
      throw new IllegalArgumentException("Denominator must not be zero.");
    }
    return numerator / denominator;
  }

  public static void main(String[] args) {
    try {
      System.out.println("Quotient: " + divide(10.0, 0.0));
    } catch (IllegalArgumentException error) {
      System.out.println("Cannot calculate a quotient: " + error.getMessage());
    }
  }
}

异常是由显式检查触发的,而不是由除法运算触发的。如果零在你的业务领域中是有效值,就不应这样拒绝它;应根据应用需求处理由此得到的 Infinity 或 NaN。

使用三元运算符为浮点数零选择备用处理方式

如果调用方能清楚理解备用处理方式,可以使用三元表达式简洁地表达策略选择。此处用一条消息表示无法得到商的情况,避免把 0.0 表现得像是除以零的数学结果。

public class Main {
  public static void main(String[] args) {
    double numerator = 10.0;
    double denominator = 0.0;

    String result = denominator == 0.0
        ? "No quotient: denominator is zero."
        : Double.toString(numerator / denominator);
    System.out.println(result);
  }
}

如果方法必须返回数值,只有在业务领域明确规定其含义时才选择备用值,并提供其他方式让调用方识别这个备用值。否则,应保留 IEEE 754 运算结果,并在不允许非有限值的环节进行验证。

总结

对于整数除法,如果零是预期会遇到的输入情况,就在运算前检查除数;如果周边操作适合通过异常处理失败,则捕获 ArithmeticException。对于浮点除法,Java 遵循 IEEE 754:非零值除以带符号的零会得到带符号的 Infinity,零除以零则会得到 NaN。

选择能够保留语义的处理方式。零不被允许时,应验证浮点输入;后续计算要求有限值时,应检查运算结果是否为非有限值。三元表达式能简化备用处理,但使用它的代码应明确理解该处理方式的含义。