第一个问题,函数是应当返回null还是长度为0的数组(或集合)?
第二个问题,函数输入参数不当时,是异常还是返回null?
先看第一个问题
有两个约定我觉得应当遵守:
1.返回零长度的数组或集合而不是null(详见《Effective Java》)
理由就是,如果返回empty,就可以少了很多not-null判断:
List<Person> list = queryPerson();
if (list != null) {
for (Person p : list) {
//do something
}
}
如果queryPerson永不返回null,那代码可以这样:
List<Person> list = queryPerson();
for (Person p : list) {
//do something
}
遵守这个规则的一个例子就是Spring JdbcTemplate的query方法,在查询不到结果时,返回的是empty List:
RowMapperResultSetExtractor:
public List<T> extractData(ResultSet rs) throws SQLException {
List<T> results = (this.rowsExpected > 0 ? new ArrayList<T>(this.rowsExpected) : new ArrayList<T>());
int rowNum = 0;
while (rs.next()) {
results.add(this.rowMapper.mapRow(rs, rowNum++));
}
return results;
}
2. 不要区分null引用和empty值
引用:
“
7. 降低修改时的误解性,不埋雷
……
一个原则就是永远不要区分null引用和empty值。
”
详见
http://javatar.iteye.com/blog/1056664
但现实世界没那么理想
比如Spring,在这两个规则上,都没有统一的处理方式
org.springframework.util.StringUtils:
public static String[] tokenizeToStringArray(
String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
if (str == null) {
return null;
}
}
public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
if (str == null) {
return new String[0];
}
}
两个功能相似的函数,在str==null时,一个返回null,一个返回empty
同一个class中都不统一,很奇怪
顺便说一下这两个函数的最大不同:
String str = "a,b;c;,d";
String delimiter = ";,";
//同时把";"和","当作分隔符
String[] sa = StringUtils.tokenizeToStringArray(str, delimiter);
assertEquals(4, sa.length);
assertEquals("a", sa[0]);
assertEquals("b", sa[1]);
assertEquals("c", sa[2]);
assertEquals("d", sa[3]);
//认为";,"是一个分隔符
sa = StringUtils.delimitedListToStringArray(str, delimiter);
assertEquals(2, sa.length);
assertEquals("a,b;c", sa[0]);
assertEquals("d", sa[1]);
Apache StringUtils也有类似的方法,对应关系如下:
Apache Spring
---------------------------------------------------------
split tokenizeToStringArray
splitByWholeSeparator delimitedListToStringArray
两个函数对str==null的处理是统一了,但它认为null和""是不同的情况:
public static String[] split(String str, String separatorChars) {
return splitWorker(str, separatorChars, -1, false);
}
private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return ArrayUtils.EMPTY_STRING_ARRAY; //that is, new String[0]
}
}
//splitByWholeSeparatorWorker在这方面跟split一样
再看看Apache ArrayUtils:
public static int[] toPrimitive(Integer[] array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return EMPTY_INT_ARRAY;
}
}
同样是区分了null和empty
所以,保险起见,对数组和集合还是要加上not-null判断,虽然代码丑了一点;除非代码都是你自己写的或者你看过源码了确保永不返回null
第二个问题
Apache FileUtils和IOUtils,对输入参数为null的处理,很多时候是抛出异常,但有时也会“静静的失败”
Apache FileUtils:
//抛出异常
public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
if (srcDir == null) {
throw new NullPointerException("Source must not be null");
}
if (srcDir.exists() && srcDir.isDirectory() == false) {
throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
}
//...
}
//注意到这个方法没有考虑file==null的情况
public static void writeLines(File file, String encoding, Collection<?> lines, String lineEnding, boolean append)
throws IOException {
FileOutputStream out = null;
try {
out = openOutputStream(file, append);
final BufferedOutputStream buffer = new BufferedOutputStream(out);
IOUtils.writeLines(lines, lineEnding, buffer, encoding);
buffer.flush();
out.close(); // don't swallow close Exception if copy completes normally
} finally {
IOUtils.closeQuietly(out);
}
}
//what if "file==null" ?
public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file + "' exists but is a directory");
}
//...
}
return new FileOutputStream(file, append);
}
Apache IOUtils:
//不抛异常
public static void writeLines(Collection<?> lines, String lineEnding, OutputStream output, Charset encoding)
throws IOException {
if (lines == null) {
return;
}
//...
}
Apache BeanUtils:
//不抛异常
public static void populate(Object bean, Map properties)
throws IllegalAccessException, InvocationTargetException
{
BeanUtilsBean.getInstance().populate(bean, properties);
}
public void populate(Object bean, Map properties)
throws IllegalAccessException, InvocationTargetException {
// Do nothing unless both arguments have been specified
if ((bean == null) || (properties == null)) {
return;
}
//...
}
看来这个问题也是见仁见智
如果你认为NullPointerException或者IllegalArgumentException有必要通知调用方,那就抛异常,特别是调用方想知道为什么调用失败:
e.g. File存在但没有写权限
e.g. File本应该是文件但传入的是目录
个人总结:
应该采取“防御式编程”,怀疑一切
分享到:
相关推荐
如果变量不存在或者其值等价于逻辑假(如0、空字符串、NULL、FALSE等),`empty()` 返回 `true`;否则返回 `false`。这里的“空”不仅仅是变量未定义,也包括变量值为0或FALSE等情况。表格中的对应结果如下: ``` $...
在ASP(Active Server Pages)开发中,理解和区分`Null`、`Empty`和`Nothing`是非常重要的,因为它们各自代表不同的空值状态,且在处理时有着特定的规则。接下来,我们将深入探讨这三个概念的区别以及如何进行正确的...
在处理数组元素时,比如表单提交的场景,`empty()` 适合用来检查变量是否有非空值,例如 `$_REQUEST['status'] = 0`,`empty($_REQUEST['status'])` 返回 `TRUE`。而 `isset()` 则用于确认变量是否已定义,即使变量...
2. **当变量值为`null`时**:如果变量已经被定义,但其值为`null`,`empty`操作符同样会返回`true`。 3. **当变量为字符串且长度为0时**:如果变量是一个字符串类型,并且该字符串的长度为0(即空字符串),那么`...
一旦使用 `unset()`,变量将不再存在,之后的 `isset()` 和 `empty()` 都会返回 `false`,而 `is_null()` 无法使用,因为它不再是一个有效的变量。 ```php $a = "Hello"; unset($a); if (isset($a)) { echo ...
- `empty` 和 `isset` 都会在变量未定义时抛出错误,而 `is_null` 可以接受未定义的变量,但会返回 `false`。 - `empty` 和 `isset` 接受的参数必须是变量,而 `is_null` 可以接受变量、常量、表达式等。 **使用...
当数组未被定义或者其值等价于FALSE(包括NULL)时,`empty()`返回TRUE。所以,这个函数也可以用来检查数组是否为NULL: ```php $array = NULL; if (empty($array)) { echo "数组是NULL"; } else { echo "数组...
因此,空字符串、0、null以及false都会使empty()返回true,除了0之外,因为0在布尔上下文中有意义,被认为是true。 false是布尔值的一种,它在逻辑上与true相反。在比较中,false不等于0、空字符串或null。然而,当...
由于null在布尔上下文中也是被视为假(false),所以使用empty()来检查null变量也会返回true。 6. false和empty: 由于false是一个布尔值,在使用empty()函数进行检查时同样会返回true。 7. 空字符串和empty: 空...
如果 变量 是非空或非零的值,则 empty() 返回 FALSE。换句话说,””、0、”0″、NULL、FALSE、array()、var $var、未定义;以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE。 代码示例: $a ...
这通常涉及到自定义一个函数来判断变量是否为 Null 或者 Empty,然后根据结果决定是否返回默认值或进行其他处理。 示例代码展示了如何使用 VBA(Visual Basic for Applications)编写这样的函数: ```vb Public ...
如果变量不存在、值为null、0、''、false或非数组类型的空数组,empty()都会返回true。 - `is_null()`:这个函数专门用来判断变量是否为null,其他任何值都不会使其返回true。 - `isset()`:该函数用于检查变量...
- empty($e) 返回true,因为$e是null。 - empty($f) 返回true,因为$f是一个空数组。 其次,is_null()是一个函数,它用于检查变量是否为NULL。与其他两种检测方法不同,is_null()只检查变量是否被明确地赋值为NULL...
由于Redis可能返回`ngx.null`,我们需要同时检查`ngx.null`和`nil`。如果`access_token`等于`ngx.null`或`nil`,说明没有有效的token,可以执行清理或错误处理的逻辑。如果`access_token`非空,通常我们会进一步处理...
Optional 是 Java 8 中引入的新特性,旨在解决空指针异常(Null Pointer Exception,NPE)这个长期困扰开发者的问题。下面我们将对 Optional 的基本概念、使用方法、优点等进行详细的介绍。 Optional 的基本概念 ...