如何在创建Java对象前校验参数?以点坐标校验为例
Java对象创建前的合法性校验问题
场景与现有代码
现有一个计算两点距离的程序,包含Cliente.java(负责输入输出)和Ponto.java(封装点坐标与距离计算)。
Cliente.java 代码
import java.util.Scanner; public class Cliente { public static void main(String[] args) { Scanner sc = new Scanner(System.in); Ponto a = new Ponto(sc.nextDouble(), sc.nextDouble()); Ponto b = new Ponto(sc.nextDouble(), sc.nextDouble()); System.out.println((int) Math.floor(a.dist(b))); sc.close(); } }
你编写的有问题的 Ponto.java 代码
class Ponto { private double x, y; check(x); check(y); public Ponto(double x, double y) { this.x = x; this.y = y; } public double dist(Ponto p) { double dx = x - p.x; double dy = y - p.y; return Math.sqrt(dx * dx + dy * dy); } public static void check(double x, double y) { if (x < 0 || y < 0) { System.out.println("iv"); } } }
需求与问题
需求是:创建Ponto对象前必须校验x、y坐标是否大于0,校验不通过则输出"iv"且不创建对象。但你编写的代码报错,且其他写法总是先创建对象再校验,不符合要求。
输入输出示例
- 合法输入:
输出:0 0 2 02 - 非法输入:
输出:-1.0 1.0 -1.0 1.0iv
代码错误分析
- 语法错误:类体中直接写
check(x); check(y);是不允许的,Java类的成员区域(变量、方法、构造器之外)不能直接执行方法调用语句,只能在方法、构造器或初始化块内执行。 - 校验逻辑无效:即使
check方法能执行,它只是输出"iv",但没有阻止对象的创建——构造器依然会完成赋值,非法坐标的对象还是会被实例化。 - 构造器未做校验:当前构造器直接赋值,完全没有对坐标合法性做判断,导致非法对象被创建。
解决方案
方案1:静态工厂方法(推荐)
将构造器私有化,通过静态工厂方法控制对象创建流程,在工厂方法中完成校验,不合法则输出提示并返回null。
修改后的 Ponto.java
class Ponto { private double x, y; // 私有构造器,外部无法直接new创建对象 private Ponto(double x, double y) { this.x = x; this.y = y; } public double dist(Ponto p) { double dx = x - p.x; double dy = y - p.y; return Math.sqrt(dx * dx + dy * dy); } // 静态工厂方法:负责校验并创建合法对象 public static Ponto create(double x, double y) { if (x < 0 || y < 0) { System.out.println("iv"); return null; } return new Ponto(x, y); } }
修改后的 Cliente.java
import java.util.Scanner; public class Cliente { public static void main(String[] args) { Scanner sc = new Scanner(System.in); Ponto a = Ponto.create(sc.nextDouble(), sc.nextDouble()); Ponto b = Ponto.create(sc.nextDouble(), sc.nextDouble()); // 仅当两个对象都合法时,才计算并输出距离 if (a != null && b != null) { System.out.println((int) Math.floor(a.dist(b))); } sc.close(); } }
方案2:构造器抛出异常
在构造器中先做校验,不合法则输出提示并抛出异常,终止对象创建流程,外部捕获异常避免程序崩溃。
修改后的 Ponto.java
class Ponto { private double x, y; public Ponto(double x, double y) { if (x < 0 || y < 0) { System.out.println("iv"); // 抛出异常终止对象创建 throw new IllegalArgumentException("坐标不能为负数"); } this.x = x; this.y = y; } public double dist(Ponto p) { double dx = x - p.x; double dy = y - p.y; return Math.sqrt(dx * dx + dy * dy); } }
修改后的 Cliente.java
import java.util.Scanner; public class Cliente { public static void main(String[] args) { Scanner sc = new Scanner(System.in); try { Ponto a = new Ponto(sc.nextDouble(), sc.nextDouble()); Ponto b = new Ponto(sc.nextDouble(), sc.nextDouble()); System.out.println((int) Math.floor(a.dist(b))); } catch (IllegalArgumentException e) { // 无需额外输出,构造器已输出"iv" } finally { sc.close(); } } }
内容的提问来源于stack exchange,提问作者Alexandre Santos
相关产品推荐
相关产品推荐

