简体   繁体   English

返回空列表时的良好编程习惯

[英]Good programming practice while returning empty list

List<String> doSomething(String input){
  if(input == null){
     return Collections.emptyList();
  }

  List<String> lst = getListfromSomewhereElse(input)
  if(lst.isEmpty(){
     return Collections.emptyList(); //Approach 1
     // return lst;  //Return same empty list
   }
   // do some more processing on lst
   return lst;
}

I prefer approach 1, coz its more readable and explicit. 我更喜欢方法1,因为它更具可读性和明确性。 What is better approch 1 or 2? 什么是更好的方法1或2?

Question is if the list is empty should i return same list or explicitly create new empty list and return 问题是列表是否为空,我应该返回相同的列表还是显式创建新的空列表并返回

Collections.emptyList() return one constant member of Collections, so it takes no excessive time (can be optimized by JIT) and memory. Collections.emptyList()返回Collections的一个常量成员,因此不花费过多时间(可以通过JIT优化)和内存。

On the other side return of getListfromSomewhereElse possibly locks empty list returned from other code. 另一方面,getListfromSomewhereElse的返回可能会锁定从其他代码返回的空列表。 Potentially you can get any list class and potentially it can take a bit of memory. 可能您可以获得任何列表类,并且可能会占用一些内存。 Generally it's not a problem, as this method is also derived, reviewed and tested by your own team, but who knows what happens in outer libraries? 通常这不是问题,因为此方法也由您自己的团队派生,审查和测试,但是谁知道外部库中发生了什么?

For example, getListfromSomewhereElse can read really large file into memory and then remove all elements from it. 例如,getListfromSomewhereElse可以将很大的文件读入内存,然后从其中删除所有元素。 So, empty list will hold thousands elements capacity unless you/them know its structure and get rid of excessive capacity. 因此,空列表将容纳数千个元素,除非您/他们知道其结构并摆脱了过多的能力。 Approach 1 will simply overcome this by usage of already existing constant list. 方法1将通过使用已经存在的常量列表简单地克服这一问题。

As a side note, if you process list elements in java 8 stream style, you naturally get new list with .collect(Collectors.toList()) step. 附带说明一下,如果您以Java 8流样式处理列表元素,则自然可以通过.collect(Collectors.toList())步骤获得新列表。 But JDK developers don't force emptyList in this case. 但是在这种情况下,JDK开发人员不会强制emptyList。

So, unless you are sure in getListfromSomewhereElse, you better return Collections.emptyList() (or new ArrayList() or whatever list type you return by method contract). 因此,除非您确定在getListfromSomewhereElse中,否则最好返回Collections.emptyList()(或新的ArrayList()或通过方法协定返回的任何列表类型)。

I would prefer 我会比较喜欢

List<String> doSomething(String input) {
    List<String> list = new ArrayList<String>();

    if (input != null) {
        List<String> listFromSomewhereElse = getListfromSomewhereElse(input);
        list.addAll(listFromSomewhereElse);
    }

    return list;
}

Keep in mind that Collections.emptyList() is unmodifiable. 请记住, Collections.emptyList()是不可修改的。 Depending on the result of getListFromSomewhereElse a client of doSomething might be confused that it can sometimes modify the list it gets and under some other situation it throws an UnsupportedOperationException . 取决于getListFromSomewhereElse的结果, getListFromSomewhereElse doSomething的客户端可能会感到困惑,因为它有时可以修改其获取的列表,而在某些其他情况下,它将引发UnsupportedOperationException Eg 例如

List<String> list = someClass.doSomething(null);
list.add("A");

will throw UnsupportedOperationException 将抛出UnsupportedOperationException

while

List<String> list = someClass.doSomething("B");
list.add("A");

might work depending on the result of getListFromSomewhereElse 可能会根据getListFromSomewhereElse的结果工作

It's very seldom necessary to do (pseudocode): 很少要做(伪代码):

if(input list is empty) {
    return an empty list
} else {
    map each entry in input list to output list
}

... because every mainstream way of mapping an input list to an output list produces an empty list "automatically" for an empty input. ...因为将输入列表映射到输出列表的每种主流方式都会为空输入“自动”生成一个空列表。 For example: 例如:

List<String> input = Collections.emptyList();
List<String> output = new ArrayList<>();
for(String entry : input) {
    output.add(entry.toLowerCase());
}
return output;

... will return an empty list. ...将返回一个空列表。 To treat an empty list as a special case makes for wasted code, and less expressive code. 将空列表视为特殊情况会浪费代码,而导致表达力较低。

Likewise, the modern Java approach of using Stream s does the same: 同样,使用Stream的现代Java方法具有相同的功能:

List<String> output = input.stream()
   .map( s -> s.toLowerCase())
   .collect(Collectors.toList());

... will create an empty List in output , with no "special" handling for an empty input. ...将在output创建一个空列表,对空输入不进行任何“特殊”处理。


Collections.emptyList() returns a class that specifically implements an immutable, empty list. Collections.emptyList()返回一个专门实现不可变的空列表的类。 It has a very simple implementation, for example its size() is just return 0; 它有一个非常简单的实现,例如,它的size()return 0; .

But this means your caller won't be able to modify the returned list -- only if it's empty. 但这意味着您的呼叫者将无法修改返回的列表-仅当该列表为空时。 Although immutability is a good thing, it's inconsistent to sometimes return a immutable list and other times not, and this could result in errors you detect late. 尽管不变性是一件好事,但有时返回不可变列表却有时不返回不可变列表是不一致的,这可能会导致您发现较晚的错误。 If you want to enforce immutability, to it always by wrapping the response in Collections.unmodifiableList() , or using an immutable list from a library like Guava. 如果要强制执行不变性,请始终通过将响应包装在Collections.unmodifiableList()中或使用诸如Guava之类的库中的不变列表来实现不变性。


You also test whether the input is null. 您还将测试输入是否为空。 Consider whether this is necessary. 考虑是否有必要。 Who's going to be calling the method? 谁将调用该方法? If it's just you, then don't do that! 如果只有您,那就不要这样做! If you know you're not going to do it, your code needn't check for it. 如果您知道不打算这样做,则无需检查代码。

If it's a public API for other programmers, you might need to handle nulls gratefully, but in many cases it's entirely appropriate to document that the input mustn't be null, and just let it throw a NullPointerException if it happens (or you can force one early by starting your method with Objects.requireNonNull(input) . 如果它是其他程序员的公共API,则可能需要感恩地处理null,但是在很多情况下,完全可以证明输入一定不能为null,如果发生输入,则让它抛出NullPointerException (或者您可以强制执行通过Objects.requireNonNull(input)启动方法,可以提早实现。


Conclusion: my recommendation is: 结论:我的建议是:

List<String> doSomething(String input){
  Objects.requireNonNull(input); // or omit this and let an 
                                 // exception happen further down

  return doMoreProcessingOn(getListfromSomewhereElse(input));
}

It's best if doMoreProcessingOn() produces a new List, rather than modifying input . 最好是doMoreProcessingOn()产生一个新的List,而不是修改input

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM