Java函数中的参数有效性检查

本文介绍了在Java编程中如何进行参数有效性检查,强调了参数有效性检查的重要性,并通过具体示例展示了如何使用运行时异常来实现这一目标。

在Java程序中,方法与属性是类中最基本的成员。下面的问题与方法有关:

实现一个方法的第一步是什么?

说到这里我突然想起侯耀文、赵丽蓉两位艺术家在小品《英雄母亲的一天》中有这样一段台词:

导演:您起床后做的第一件事是什么?可以随便说。
大娘一听可以随便说,笑了。
大娘(凑到导演的耳朵边,轻声地):上厕所。

在这里,我也想做一回导演,把上面的台词改一下:

编程新手:您在实现类中的一个方法时,第一步要做的事是什么?可以随便说。
编程老手一听可以随便说,笑了。
编程老手(凑到新手的耳朵边,轻声地):参数有效性检查。

大娘的回答铁定不是导演希望听到的,编程老手的回答恐怕也不是新手想要得到的。原因很简单,与正题无关。但是参数有效性检查之于方法实现的重要性决不亚于早上起来上厕所,个中原因只可意会,不可言传。这里要讨论的是如何在Java中进行参数有效性检查。

说到参数有效性检查,不得不说一下运行时异常。Java有两种异常:一般异常与运行时异常。继承自Exception的异常称为一般异常,继承自RuntimeException的异常称为运行时异常。与一般异常最大的不同之处在于,函数调用方可以不必处理实现方抛出的运行时异常。 但是异常的抛出通常会被当成一种错误的发生。如果调用方可以不用处理运行时异常,那就意味着调用方必须尽量避免实现方抛出运行时异常。 例如:

[java]  view plain  copy
 
  1. public static boolean equalObject(Object obj1, Object obj2) {  
  2.     return obj1.equals(obj2);  
  3. }  

 

上述代码在obj1为null的场合下会抛出NullPointerException,为了避免这种情况发生,正确的写法应该是:

 

[java]  view plain  copy
 
  1. public static boolean equalObject(Object obj1, Object obj2) {  
  2.     return (obj1 != null && obj1.equals(obj2));  
  3. }  



可以看出,运行时异常是对函数调用方一种无形的约束,这种约束方式正好符合参数有效性检查的要求,即调用方法时必须提供正确的参数,否则就会导致系统崩溃。例如我们通过物体的质量计算其重力值。实现方法如下:

 

 

[java]  view plain  copy
 
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         System.out.println(getGravity(1.0));  
  4.     }  
  5.   
  6.     public static double getGravity(double mass) {  
  7.         return mass * 9.82;  
  8.     }  
  9. }  

 

 

我们知道一般情况下一个1.0千克的物体其重力为9.82牛顿,但质量为负数的物体呢?物理常识告诉我们,世界上不存在质量为0或小于0的物体,据此我们应该如何完善重力的计算方法呢?

计算重力的第一步应该是对质量进行参数有效性检查。Java SDK中提供了许多种运行时异常,与参数有效性检查相关的异常是IllegalArgumentException。代码实现可以如下:

 

[java]  view plain  copy
 
  1. public static double getGravity(double mass) {  
  2.     // 参数有效性检查  
  3.     if (mass <= 0) {  
  4.         throw new IllegalArgumentException("无效质量:" + mass);  
  5.     }  
  6.   
  7.     return mass * 9.82;  
  8. }  

 

 

当我们调用这样一个计算重力的方法时,应该尽量传递有效的质量值。当我们传递一个负值给此方法时,系统将会以抛出异常的方式退出。如:

[java]  view plain  copy
 
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.   
  4.         System.out.println(getGravity(1.0)); // 有效的质量  
  5.         // 我们应该尽量避免下面的调用  
  6.         // System.out.println(getGravity(-1.0)); // 无效的质量  
  7.     }  
  8.   
  9.     public static double getGravity(double mass) {  
  10.   
  11.         // 参数有效性检查  
  12.         if (mass <= 0) {  
  13.             throw new IllegalArgumentException("无效质量:" + mass);  
  14.         }  
  15.   
  16.         return mass * 9.82;  
  17.     }  
  18. }  

 

参数有效性检查应该作为常识来掌握,特别是Java中特有的参数有效性检查。上面介绍的是最基本的用法,当然我们也可以利用第三方程序库(如Apache Commons Lang 库的Validate类)来简化参数有效性检查的过程。

 

 

每当编写方法或者构造器的时候,应该考虑他的参数有哪些限制。应该把这些限制写到文档中,并且在这个方法体的开头处,通过显式的检查来实施这些限制。养成这样的习惯是非常重要的。
demo:
1\对于公有的方法,要用Javadoc的@throws标签(tag)在文档中说明违反参数值限制会抛出异常。
手工抛出异常,并且添加@throws注解说明原因

 

[java]  view plain  copy
 
  1. /** 
  2.  * hello..... 
  3.  * @param m 
  4.  * @return 
  5.  * @throws NullPointerException if m is null 
  6.  * @throws ArithmeticException if m is less than or equals to 0 
  7.  */  
  8. public BigInteger mod(BigInteger m) {  
  9.     if(m == null){  
  10.         throw new NullPointerException("m is null:" + m);  
  11.     }  
  12.     if (m.signum() <= 0) {  
  13.         throw new ArithmeticException("Modulus <= 0: " + m);  
  14.     }  
  15.     // Do something  
  16.     return null;  
  17. }  


2\对于未被导出的方法(unexported method),作为包的创建者,你可以控制这个方法将在哪些情况下被使用,因此你可以,也应该确保只将有效的参数传递进来。
因此,非公有的方法通常应该使用断言(assertion)来检查他们的参数。
通过将-ea(或者-enableassertions)标记传递给java解释器,来启动他们。 
(一般来说 assert 在开发的时候是检查程序的安全性的,在发布的时候通常都不使用 assert 。)

 

 

[java]  view plain  copy
 
  1. /** 
  2.  *  
  3.  * @param a 
  4.  * @param offset 
  5.  * @param length 
  6.  */  
  7. private static void sort(long[] a,int offset,int length){  
  8.     assert a != null;  
  9.     assert offset >= 0 && offset <= a.length;  
  10.     System.out.println("sort do something");  
  11. }  


不同于junit里的断言方法:

 

 

[java]  view plain  copy
 
  1. private static void sort2(long[] a, int offset, int length) {  
  2.     Assert.assertTrue("a is null", a != null);  
  3.     Assert.assertTrue(offset >= 0 && offset <= a.length);  
  4.     System.out.println("sort do something");  
  5. }  

 

 

### Java 实现收货地址有效性检查 为了确保收货地址的有效性,在电商和物流行业中通常会采用多种方法来进行验证。以下是几种常见的校验方式及其对应的Java实现。 #### 1. 基本格式校验 最基础的方式是对输入字符串进行简单的正则表达式匹配,以确认其是否符合一般意义上的地址结构[^1]。 ```java public class AddressValidator { private static final String ADDRESS_REGEX = "^[a-zA-Z0-9\\u4e00-\\u9fa5,./;:'\"!@#$%^&*()_+-=<>?/|{}~` ]+$"; public boolean isValidFormat(String address) { return address.matches(ADDRESS_REGEX); } } ``` 此段代码定义了一个名为 `AddressValidator` 的类,并在其内部实现了用于检测地址格式的方法 `isValidFormat()` 。该函数接收一个参数——待检验的地址字符串;如果传入的内容能够与预设模式相吻合,则返回真值表示合法,反之亦然。 #### 2. 关键词存在性校验 除了形式上的审查外,还可以进一步考察特定关键词(如省份名、城市名等地理实体名称)是否存在并位于合理位置上。这一步骤有助于排除明显错误的数据项。 ```java import java.util.Arrays; import java.util.List; public class KeywordChecker extends AddressValidator { private List<String> provinceKeywords = Arrays.asList("北京", "上海", ...); // 省份列表 @Override public boolean isValidFormat(String address){ if (!super.isValidFormat(address)) return false; for (String keyword : provinceKeywords){ if (address.contains(keyword)){ return true; } } System.out.println("未找到有效的省市区关键字"); return false; } } ``` 上述例子展示了继承自先前创建的基础验证器的新版本 `KeywordChecker` ,它增加了对于中国各省级行政区划单位名称的查找逻辑。当发现至少有一个预期中的地域术语存在于给定文本之中时即认为满足条件;否则提示用户重新填写正确的信息。 #### 3. API辅助校验 更高级别的解决方案可能涉及到调用第三方服务API接口完成精准定位以及详细解析工作。这类操作往往依赖于外部提供商所提供的Web Service端点来获取标准化后的地理位置描述[^2]。 ```java // 这里仅给出伪代码示意,实际开发需参照具体服务商文档编写相应请求处理程序 try{ HttpResponse response = HttpUtil.sendGetRequestToGeocodingService(userInputAddress); JSONObject jsonResponse = new JSONObject(response.body()); double latitude = jsonResponse.getDouble("lat"); double longitude = jsonResponse.getDouble("lng"); // 对经纬度数值做适当范围内的合理性判断... } catch(Exception e){ logger.error(e.getMessage(), e); throw new InvalidAddressException(); } ``` 通过这种方式不仅可以获得更加精确的结果反馈,而且还能顺便解决诸如拼写差异等问题带来的困扰。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值