Kiểm tra Null trong một vòng lặp nâng cao


172

Cách tốt nhất để bảo vệ chống null trong vòng lặp for trong Java là gì?

Điều này có vẻ xấu:

if (someList != null) {
    for (Object object : someList) {
        // do whatever
    }
}

Hoặc là

if (someList == null) {
    return; // Or throw ex
}
for (Object object : someList) {
    // do whatever
}

Có thể không có cách nào khác. Họ có nên đặt nó trong forcấu trúc không, nếu nó là null thì đừng chạy vòng lặp?


2
Bạn có lẽ tốt hơn hết là ném NPE. nullkhông giống như một bộ sưu tập trống.
Tom Hawtin - tackline

6
@GregMattes Làm thế nào câu hỏi tháng hai là một bản sao của câu hỏi tháng mười?
Val

1
Chỉ cần sử dụng Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley

Câu trả lời:


227

Bạn nên xác minh tốt hơn nơi bạn nhận được danh sách đó từ.

Một danh sách trống là tất cả những gì bạn cần, bởi vì một danh sách trống sẽ không thất bại.

Nếu bạn nhận được danh sách này từ một nơi khác và không biết liệu nó có ổn hay không, bạn có thể tạo một phương thức tiện ích và sử dụng nó như thế này:

for( Object o : safe( list ) ) {
   // do whatever 
 }

Và tất nhiên safesẽ là:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}

57
Lưu ý rằng Collections.emptyList () sẽ tránh phân bổ một đối tượng bổ sung (IIRC).
Jon Skeet

7
@Jon: Tôi đã luôn tự hỏi bản thân mình, việc sử dụng emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/util/rc là gì?
OscarRyz

11
IIRC = "Nếu tôi nhớ chính xác". Và vâng, có một cá thể singleton được trả về cho tất cả các lệnh gọi tới Collections.emptyList ().
ColinD

Điều này ... không thực sự trả lời câu hỏi. Tại sao nó được chấp nhận câu trả lời?
Christopher Wirt

1
@ChristopherWirt vì nó trả lời câu hỏi: D
Tarik

100

Bạn có khả năng có thể viết một phương thức trợ giúp trả về một chuỗi trống nếu bạn chuyển qua null:

public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
    return iterable == null ? Collections.<T>emptyList() : iterable;
}

Sau đó sử dụng:

for (Object object : emptyIfNull(someList)) {
}

Tôi không nghĩ rằng tôi thực sự làm điều đó mặc dù - tôi thường sử dụng hình thức thứ hai của bạn. Cụ thể, "hoặc ném ex" rất quan trọng - nếu nó thực sự không nên rỗng, bạn chắc chắn nên ném một ngoại lệ. Bạn biết rằng một cái gì đó có sai đi, nhưng bạn không biết được mức độ thiệt hại. Hủy bỏ sớm.


3
Tôi sẽ thay đổi tham số danh sách <T> lặp lại thành lặp có thể lặp lại <T>, vì không phải mọi lần lặp đều là một danh sách.
Lombo

Hãy cẩn thận khi sử dụng phương pháp này: vì sử dụng lớp Bộ sưu tập, việc sử dụng phương pháp này liên quan đến danh sách của bạn là bất biến
Tanorix

@tanorix: Bằng cách nào?
Jon Skeet

@JonSkeet bạn có thể thấy rằng voidList () của lớp Bộ sưu tập trả về một danh sách không thay đổi: docs.oracle.com/javase/8/docs/api/java/util/, vì vậy nếu người dùng không muốn có danh sách của mình thì không thể thay đổi có vấn đề
Tanorix

@tanorix: Nhưng quan điểm của câu hỏi này là về việc lặp lại giá trị trả về. Điều đó không sửa đổi nó. Đó là lý do tại sao kiểu trả về emptyIfNullIterable<T>- có removephương pháp không may trên đó Iterator<T>, nhưng đó là khía cạnh duy nhất có thể thay đổi của nó (và nếu bạn có một bộ sưu tập trống, tại sao bạn lại cố gắng loại bỏ bất cứ thứ gì khỏi nó?) lại phản đối ở đây.
Jon Skeet

29

Đã là năm 2017 và bây giờ bạn có thể sử dụng Bộ sưu tập Apache Commons4

Việc sử dụng:

for(Object obj : ListUtils.emptyIfNull(list1)){
    // Do your stuff
}

Bạn có thể thực hiện kiểm tra an toàn null cho các lớp Collection khác với CollectionUtils.emptyIfNull.


2
Sẽ làm việc mặc dù tạo đối tượng danh sách không cần thiết. Một CollectionUtils.ifNotEmpty có thể dài dòng hơn nhưng hiệu quả hơn và nhanh hơn. Không có vấn đề gì nhiều ...
Lawrence

2
Trong năm 2017, tôi sẽ mong đợi List.empty IfNull (list1)
Dima

3
@Lawrence, phương thức này không tạo ra các đối tượng danh sách mới, nó sử dụng Collections.emptyList()nội bộ, đến lượt nó luôn trả về cùng một danh sách trống không thể thay đổi được preallocated.
Yoory N.

Điều gì sẽ xảy ra nếu bạn gọi myobject.getCompiances (). GetAddresses () và cả hai trả về một Danh sách và cả hai đều có thể là null?
bột366

9

Với Java 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}

1
Nó dài dòng hơn so với toán tử ternary đơn giản như someList != null ? someList : Collections.emptyList()và cũng tạo ra và ngay lập tức ném đi một thể hiện của Optionalđối tượng.
Yoory N.

2
làm thế nào những dòng quái vật này thanh lịch hơn một câu lệnh if (someList == null) đơn giản. Hãy viết một ứng dụng ngân hàng trong một dòng ...
Andreas Panagiotidis

8

Sử dụng ArrayUtils.nullToEmptytừ commons-langthư viện cho Mảng

for( Object o : ArrayUtils.nullToEmpty(list) ) {
   // do whatever 
}

Chức năng này tồn tại trong commons-langthư viện, được bao gồm trong hầu hết các dự án Java.

// ArrayUtils.nullToEmpty source code 
public static Object[] nullToEmpty(final Object[] array) {
    if (isEmpty(array)) {
        return EMPTY_OBJECT_ARRAY;
    }
    return array;
}

// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
    return array == null || array.length == 0;
}

Đây giống như câu trả lời được đưa ra bởi @OscarRyz, nhưng vì lợi ích của câu thần chú DRY , tôi tin rằng nó đáng để lưu ý. Xem trang dự án commons-lang . Đây là tài liệunguồnnullToEmpty API

Mục Maven để đưa commons-langvào dự án của bạn nếu nó chưa có.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

Thật không may, commons-langkhông cung cấp chức năng này cho Listcác loại. Trong trường hợp này, bạn sẽ phải sử dụng một phương thức trợ giúp như đã đề cập trước đó.

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}

7

Nếu bạn nhận được điều đó Listtừ một cuộc gọi phương thức mà bạn thực hiện, thì đừng trả về null, trả về một khoảng trống List.

Nếu bạn không thể thay đổi việc thực hiện thì bạn sẽ bị kẹt với nullkiểm tra. Nếu không nên null, hãy ném ngoại lệ.

Tôi sẽ không dùng phương thức trợ giúp trả về một danh sách trống vì đôi khi nó có thể hữu ích nhưng sau đó bạn sẽ quen với việc gọi nó trong mỗi vòng lặp mà bạn có thể ẩn một số lỗi.


4

Tôi đã sửa đổi câu trả lời ở trên, vì vậy bạn không cần phải chọn từ Object

public static <T> List<T> safeClient( List<T> other ) {
            return other == null ? Collections.EMPTY_LIST : other;
}

và sau đó chỉ cần gọi Danh sách bằng cách

for (MyOwnObject ownObject : safeClient(someList)) {
    // do whatever
}

Giải thích: MyOwnObject: Nếu List<Integer>thì MyOwnObject sẽ là Integer trong trường hợp này.


1

Một cách khác để bảo vệ hiệu quả đối với null trong vòng lặp for là bọc bộ sưu tập của bạn với Google Guava Optional<T>vì điều này, hy vọng, làm cho khả năng một bộ sưu tập trống có hiệu quả rõ ràng vì khách hàng sẽ kiểm tra xem bộ sưu tập có hiện diện hay không Optional.isPresent().


1

Đối với bất kỳ ai không quan tâm đến việc viết phương pháp an toàn null tĩnh của riêng họ, bạn có thể sử dụng: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Ví dụ:

    for (final String item : 
    (List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }

ObjectUtils.default IfNull JavaDoc


Đối với tôi, câu trả lời này là thanh lịch nhất
Truong Nguyen

0

Sử dụng, CollectionUtils.isEmpty(Collection coll)phương pháp kiểm tra an toàn Null nếu bộ sưu tập được chỉ định trống.

cho điều này import org.apache.commons.collections.CollectionUtils.

Phụ thuộc Maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.