编写过很多Java文章的人可能都编写了以条件为开头的方法,这些条件可以在继续进行该方法的其余实现之前,先验证提供的参数或要操作的对象的状态。 这些会增加方法的冗长性,有时,尤其是在有多个检查的情况下,几乎会淹没该方法有趣的业务逻辑。 减少这种混乱的一种方法是使用Java断言 ,但是默认情况下会在运行时禁用它们。 实际上,出于这个原因, 建议 “不要在公共方法中使用断言进行参数检查”,而应使用适当的运行时异常 。 Guava提供了一个方便的Preconditions类,该类具有断言的美学优势,但它使用常规的Java异常机制,并且在运行时未禁用。 这篇文章提供了一些实际使用Guava的Preconditions
类的示例。
下一个代码清单显示了使用Guava的Preconditions
类制作的示例。 该示例演示了在Preconditions
类上使用静态方法检查参数是否为null,检查参数在提供的数组中的位置,检查以确保为参数提供了有效值以及检查对象的状态是否为true。调用哪种方法适合该方法的执行。 还要注意,我对Preconditions
类使用了静态导入 ,这样我就可以调用其静态方法,而不必将每次调用的范围都限定为类名。
GuavaPreconditionsDemo.java
package dustin.examples;
import static java.lang.System.err;
import static com.google.common.base.Preconditions.*;
/**
* Simple demonstration of Guava's Preconditions support.
*
* @author Dustin
*/
public class GuavaPreconditionsDemo
{
private final boolean initialized = false;
/**
* Demonstrate Guava's Preconditions.checkNotNull methods.
*
* @param parameter Parameter that is checked for null-ness.
*/
public void testForNonNullArgument(final String parameter)
{
final String localParameter = checkNotNull(parameter, 'Provided parameter is unacceptably null.');
}
public void testDivisorNotZero(final int divisor)
{
checkArgument(divisor != 0, 'Zero divisor not allowed.');
}
public void testArrayElement(final String[] strArray, final int indexNumber)
{
final int index = checkElementIndex(indexNumber, strArray.length, 'String array index number');
}
public void testArrayPosition(final String[] strArray, final int indexNumber)
{
final int index = checkPositionIndex(indexNumber, strArray.length, 'String array index number');
}
public void testState()
{
checkState(this.initialized, 'Cannot perform action because not initialized.');
}
public static void printHeader(final String newHeaderText)
{
err.println('\n==========================================================');
err.println('== ' + newHeaderText);
err.println('==========================================================');
}
/**
* Main function for executing demonstrations of Guava's Preconditions.
*/
public static void main(final String[] arguments)
{
final GuavaPreconditionsDemo me = new GuavaPreconditionsDemo();
printHeader('Preconditions.checkNotNull');
try
{
me.testForNonNullArgument(null);
}
catch (NullPointerException npe)
{
npe.printStackTrace();
}
printHeader('Preconditions.checkArgument');
try
{
me.testDivisorNotZero(0);
}
catch (IllegalArgumentException illArgEx)
{
illArgEx.printStackTrace();
}
printHeader('Preconditions.checkElementIndex');
try
{
me.testArrayElement(new String[]{'Dustin', 'Java'}, 3);
}
catch (IndexOutOfBoundsException ioobEx)
{
ioobEx.printStackTrace();
}
printHeader('Preconditions.checkPositionIndex');
try
{
me.testArrayPosition(new String[]{'Dustin', 'Java'}, 3);
}
catch (IndexOutOfBoundsException ioobEx)
{
ioobEx.printStackTrace();
}
printHeader('Preconditions.checkState');
try
{
me.testState();
}
catch (IllegalStateException illStateEx)
{
illStateEx.printStackTrace();
}
}
}
上面的代码清单中演示的每种情况都检查了方法参数或调用方法所针对的对象状态的前提条件,而无需使用“嘈杂”的条件语句。 静态导入的使用允许非常简洁地表达要检查的条件,该类的大部分是“主要”功能,在这种情况下用作“测试驱动程序”。 我将调用放在try-catch块中,以确保执行了所有演示。 接下来显示运行以上命令的输出。
执行以上类的输出
==========================================================
== Preconditions.checkNotNull
==========================================================
java.lang.NullPointerException: Provided parameter is unacceptably null.
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:204)
at dustin.examples.GuavaPreconditionsDemo.testForNonNullArgument(GuavaPreconditionsDemo.java:22)
at dustin.examples.GuavaPreconditionsDemo.main(GuavaPreconditionsDemo.java:62)
==========================================================
== Preconditions.checkArgument
==========================================================
java.lang.IllegalArgumentException: Zero divisor not allowed.
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:88)
at dustin.examples.GuavaPreconditionsDemo.testDivisorNotZero(GuavaPreconditionsDemo.java:27)
at dustin.examples.GuavaPreconditionsDemo.main(GuavaPreconditionsDemo.java:72)
==========================================================
== Preconditions.checkElementIndex
==========================================================
java.lang.IndexOutOfBoundsException: String array index number (3) must be less than size (2)
at com.google.common.base.Preconditions.checkElementIndex(Preconditions.java:301)
at dustin.examples.GuavaPreconditionsDemo.testArrayElement(GuavaPreconditionsDemo.java:32)
at dustin.examples.GuavaPreconditionsDemo.main(GuavaPreconditionsDemo.java:82)
==========================================================
== Preconditions.checkPositionIndex
==========================================================
java.lang.IndexOutOfBoundsException: String array index number (3) must not be greater than size (2)
at com.google.common.base.Preconditions.checkPositionIndex(Preconditions.java:351)
at dustin.examples.GuavaPreconditionsDemo.testArrayPosition(GuavaPreconditionsDemo.java:37)
at dustin.examples.GuavaPreconditionsDemo.main(GuavaPreconditionsDemo.java:92)
==========================================================
== Preconditions.checkState
==========================================================
java.lang.IllegalStateException: Cannot perform action because not initialized.
at com.google.common.base.Preconditions.checkState(Preconditions.java:145)
at dustin.examples.GuavaPreconditionsDemo.testState(GuavaPreconditionsDemo.java:42)
at dustin.examples.GuavaPreconditionsDemo.main(GuavaPreconditionsDemo.java:102)
当违反指定条件时,不同的静态Preconditions
方法会引发不同类型的运行时异常。 他们会抛出异常,这些异常往往适合于被违反的特定案例。 这意味着在大多数情况下, Preconditions
静态方法调用的结果与可能针对该条件显式抛出的结果相同,但是使用更少的代码进行检查并引发异常。 我没有在本文中显示它,但是这些静态方法的重载版本还允许提供字符串参数以填充带图案的String中的占位符。 这有助于将与错误条件关联的值放在异常消息中。
结论
番石榴简化了编码,并提高了合同检查方法的流畅性和可读性。 它提供了断言的简洁语法的优点,以及传统的抛出运行时异常的优点。
参考:来自JCG合作伙伴 Dustin Marx的Guava前提条件课程,来自Inspired by Actual Events博客。
翻译自: https://www.javacodegeeks.com/2012/11/guava-preconditions-class.html