Java 断言编程第一部分
介绍
您可能在通过JUnit等框架或AssertJ等第三方断言库进行单元测试时使用过断言方法。
但是你知道 Java 有一个内置的断言机制吗?如果你知道,你以前用过它吗?
Java 的断言早在 Java 1.4 中就已引入,与单元测试框架的断言方法一样,它们使用布尔表达式,如果计算结果为 false,则抛出异常。
但是,它们可以在代码中的任何位置使用(由于一些良好的做法而有一些限制)并且具有与其他断言方法不同的语义。
断言会检验您认为真实的事情。
它可能是你认为不可能发生的事情、执行一段代码后必须出现的事情、或者是你的代码必须为真的事情。
这听起来可能是一个简单的概念,但它是理解和正确使用断言的关键。
在本系列指南中,我将向您展示如何使用 Java 断言机制、启用和禁用断言的语法和选项、良好的断言实践、使用断言的契约式设计编程风格,以及断言如何区分异常和单元测试。
使用断言
让我们从如何使用断言的基础开始。
断言使用保留的assert关键字。其语法如下:
      assert booleanExpression;
    
以下是一个例子:
      private double calculateInterest(double amount) {
  assert amount > 0 && amount <= 1_000;
  
  double interest = 0.0;
  
  // calculate interest
  
  return interest;
}
    
如果条件计算结果为false ,则会抛出java.lang.AssertionError类型的异常。
这意味着上面的例子等同于下面的例子:
      private double calculateInterest(double amount) {
  if(amount > 0 && amount < 1_000) {
    throw new AssertionError();
  }
  
  double interest = 0.0;
  
  // calculate interest
  
  return interest;
}
    
为什么AssertionError是Error的子类而不是RuntimeException的子类?
因为我们不应该捕获Error及其子类。
尝试从断言错误中恢复是没有意义的。这样的错误意味着程序没有在程序员假设的条件下运行。这很可能会导致继续执行导致更多错误。
因此错误将导致程序停止,并打印堆栈跟踪,例如:
      Exception in thread "main" java.lang.AssertionError
	at com.example.AssertTest.calculateInterest(AssertTest.java:6)
	at com.example.AssertTest.main(AssertTest.java:16)
    
那可能不是很有用。
但是,assert 语句也可以接收消息:
      assert booleanExpression : "Message about the error";
    
例如,如果以下断言失败:
      private double calculateInterest(double amount) {
  assert 
    amount > 0 && amount < 1_000 
    : 
    "Amount should be between 0 and 1,000: " 
        + amount;
  
  // ...
}
    
类似下面的内容将被打印到标准输出:
      Exception in thread "main" java.lang.AssertionError: Amount should be between 0 and 1,000: -11.0
	at com.example.AssertTest.calculateInterest(AssertTest.java:6)
	at com.example.AssertTest.main(AssertTest.java:16)
    
再次强调,上面的例子等同于:
      if(amount > 0 && amount < 1_000) {
    throw new AssertionError(
      "Amount should be between 0 and 1,000: " 
        + amount
    );
  }
  
  // ...
}
    
大多数情况下,你会使用String,但是如果你查看AssertionError的构造函数,你会发现它也可以采用其他可以转换为字符串的类型:
      AssertionError(boolean detailMessage)
AssertionError(char detailMessage)
AssertionError(double detailMessage)
AssertionError(float detailMessage)
AssertionError(int detailMessage)
AssertionError(long detailMessage)
AssertionError(Object detailMessage)
AssertionError(String message, Throwable cause)
    
这意味着如果这对你来说足够了,你可以使用类似如下的方法:
      private double calculateInterest(double amount) {
  assert amount > 0 && amount < 1_000 : amount;
  
  // ...
}
    
如果布尔表达式的计算结果为true,则什么也不会发生。
但是,默认情况下断言不启用。因此,即使断言失败,如果您不使用特殊标志运行程序,也不会发生任何事情。
使用-ea或enableassertions标志可以启用断言:
      java –ea AssertTest
// Or
java –enableassertions AssertTest
    
这将在我们程序中除 Java 类(系统类)之外的所有类中启用断言。
如果您想在 Java 类中启用断言,您可以使用-esa或enablesystemassertions标志:
      java –esa AssertTest
// Or
java –enablesystemassertions AssertTest
    
您还可以只为一个类启用断言:
      java –ea:com.example.MyOtherClass AssertTest
    
或者在特定命名的包及其任何子包中:
      java –ea:com.example... AssertTest
    
或者在当前工作目录中的默认包中:
      java –ea:... AssertTest
    
还有一个禁用断言的选项:
      java –da AssertTest
// Or
java –disableassertions AssertTest
    
以及在 Java 类中禁用断言的相应选项:
      java –dsa AssertTest
// Or
java –disablesystemassertions AssertTest
    
您可能想知道,如果默认情况下断言是禁用的,为什么我们还会有这个选项?
好吧,您可以使用相同的ea和esa标志选项来禁用一个类或整个包。
你也可以将它们组合起来。例如,你可以在com.example包中的所有类中启用断言,但com.example.Utils类除外:
      java –ea:com.example... -da:com.example.Utils AssertTest
    
契约式设计风格和断言
Java 的断言机制可用于非正式的契约式设计编程风格。
契约式设计是一种软件设计方法,该方法将软件视为一组组件,这些组件的交互基于相互定义的义务或契约,其形式为:
- 可接受和不可接受的输入和返回值或类型
- 可能发生的错误和异常情况
- 副作用
- 先决条件
- 后置条件
- 不变量
这个概念是由Bertrand Meyer构思出来的,他基于这个概念以及其他面向对象编程的概念设计了Eiffel 编程语言。
例如,在 Eiffel 中,您可以使用以下语法来编写例程:
      processElement (e : ELEMENT) is
  require
    not e.empty
  do
    -- Perform the operation
  ensure
    e.is_processed
  end
    
与 assert 类似,require子句检查输入或先决条件,而Ensure子句检查输出或后置条件。这两个条件都是与此例程相关的合同的一部分。
但是我们也可以设置一些必须始终适用于整个类的条件(例如在调用某个方法之前和之后),而不仅仅是在某个特定时刻。这些被称为类不变量:
      invariant
  element_count > 0
    
您可以将不变量视为一种条件,它既是先决条件,又是后置条件。
这样,Eiffel 的 IDE就可以以文本格式提供该类的简短形式<font
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
 
 
                                 
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                     
                                 
                             
                                     
                                     
                                     
                                     
     
    
 
             
   
        
请先 登录后发表评论 ~