2014-10-13 28 views
8

Giả sử tôi có một biến số activities loại List<Any>?. Nếu danh sách không phải là rỗng và không rỗng, tôi muốn làm một cái gì đó, nếu không tôi muốn làm một cái gì đó khác. Tôi đã đưa ra giải pháp sau:Cách thức xử lý danh sách trống hoặc rỗng trong Kotlin

when { 
    activities != null && !activities.empty -> doSomething 
    else -> doSomethingElse 
} 

Có cách nào khác để làm điều này trong Kotlin không?

+1

Lưu ý: 'khi' có hai lựa chọn thay thế rất gần với' if' –

Trả lời

11

Đối với một số hành động đơn giản bạn có thể sử dụng toán tử gọi an toàn, giả định các hành động cũng tôn trọng không hoạt động trên một danh sách rỗng (để xử lý trường hợp của bạn của cả vô trống:

myList?.forEach { ...only iterates if not null and not empty } 

Đối với những hành động khác mà bạn có thể viết một chức năng mở rộng - hai biến thể tùy thuộc vào nếu bạn muốn nhận danh sách như this hoặc như một tham số:.

inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Unit { 
    if (this != null && this.isNotEmpty()) { 
     with (this) { func() } 
    } 
} 

inline fun <E: Any, T: Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Unit { 
    if (this != null && this.isNotEmpty()) { 
     func(this) 
    } 
} 

Mà bạn có thể sử dụng như:

fun foo() { 
    val something: List<String>? = makeListOrNot() 
    something.withNotNullNorEmpty { 
     // do anything I want, list is `this` 
    } 

    something.whenNotNullNorEmpty { myList -> 
     // do anything I want, list is `myList` 
    } 
} 

Bạn cũng có thể làm chức năng nghịch đảo:

inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): Unit { 
    if (this == null || this.isEmpty()) { 
     func() 
    } 
} 

tôi sẽ tránh chaining những bởi vì khi đó bạn đang thay thế một tuyên bố if hoặc when với một cái gì đó nhiều từ hơn. Và bạn đang nhận được nhiều hơn vào lĩnh vực mà các lựa chọn thay thế tôi đề cập dưới đây cung cấp, đó là phân nhánh đầy đủ cho các tình huống thành công/thất bại.

Lưu ý: các tiện ích này đã được tổng quát hóa thành tất cả các hậu duệ của Collections giữ các giá trị không null. Và làm việc nhiều hơn là chỉ Danh sách.

Alternatives:

Thư viện Result cho Kotlin đưa ra một cách tốt đẹp để xử lý trường hợp của bạn là "làm được điều này, hoặc là" dựa trên các giá trị phản ứng. Đối với lời hứa, bạn có thể tìm thấy điều tương tự trong thư viện Kovenant.

Cả hai thư viện này cung cấp cho bạn cách trả về các kết quả thay thế từ một hàm duy nhất và cũng để phân nhánh mã dựa trên kết quả. Họ yêu cầu bạn đang kiểm soát nhà cung cấp "câu trả lời" được thực hiện.

Đây là những lựa chọn thay thế tốt của Kotlin cho OptionalMaybe.

Khám phá các chức năng mở rộng hơn nữa (và có lẽ quá nhiều)

Phần này chỉ là để chứng minh rằng khi bạn nhấn một vấn đề như câu hỏi nêu ra ở đây, bạn có thể dễ dàng tìm thấy nhiều câu trả lời trong Kotlin để làm mã hóa theo cách bạn muốn. Nếu thế giới không dễ thương, hãy thay đổi thế giới. Nó không phải là một câu trả lời tốt hay xấu, mà là thông tin bổ sung.

Nếu bạn thích các chức năng mở rộng và muốn xem xét chaining chúng trong một biểu thức, tôi sẽ có thể thay đổi chúng như sau ...

Các withXyz hương vị trở thiswhenXyz nên trở lại một kiểu mới cho phép toàn bộ bộ sưu tập để trở thành một bộ sưu tập mới (thậm chí có thể không liên quan đến bản gốc). Kết quả là mã như sau:

val BAD_PREFIX = "abc" 
fun example(someList: List<String>?) { 
    someList?.filterNot { it.startsWith(BAD_PREFIX) } 
      ?.sorted() 
      .withNotNullNorEmpty { 
       // do something with `this` list and return itself automatically 
      } 
      .whenNotNullNorEmpty { list -> 
       // do something to replace `list` with something new 
       listOf("x","y","z") 
      } 
      .whenNullOrEmpty { 
       // other code returning something new to replace the null or empty list 
       setOf("was","null","but","not","now") 
      } 
} 

Lưu ý: Mã đầy đủ cho phiên bản này là ở phần cuối của bài viết (1)

Nhưng bạn cũng có thể đi theo một hướng hoàn toàn mới với tùy chỉnh " khác rằng" cơ chế này:

fun foo(someList: List<String>?) { 
    someList.whenNullOrEmpty { 
     // other code 
    } 
    .otherwise { list -> 
     // do something with `list` 
    } 
} 

không có giới hạn, hãy sáng tạo và tìm hiểu sức mạnh của các phần mở rộng, hãy thử những ý tưởng mới, và như bạn có thể thấy có rất nhiều biến thể như thế nào mọi người muốn mã hóa các loại tình huống . Các stdlib không thể hỗ trợ 8 biến thể của các loại phương pháp mà không bị nhầm lẫn. Nhưng mỗi nhóm phát triển có thể có các phần mở rộng phù hợp với phong cách mã hóa của chúng.

Lưu ý: Mã đầy đủ cho phiên bản này là ở phần cuối của bài viết (2)

Mẫu mã 1:Đây là mã đầy đủ cho phiên bản "xiềng xích":

inline fun <E: Any, T: Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): T? { 
    if (this != null && this.isNotEmpty()) { 
     with (this) { func() } 
    } 
    return this 
} 

inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNotNullNorEmpty(func: (T) -> R?): R? { 
    if (this != null && this.isNotEmpty()) { 
     return func(this) 
    } 
    return null 
} 

inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): T? { 
    if (this == null || this.isEmpty()) { 
     func() 
    } 
    return this 
} 

inline fun <E: Any, T: Collection<E>, R: Any> T?.whenNullOrEmpty(func:() -> R?): R? { 
    if (this == null || this.isEmpty()) { 
     return func() 
    } 
    return null 
} 

Sample code 2:đây là mã đầy đủ cho một "này bằng cách khác rằng" thư viện (với đơn vị kiểm tra):

inline fun <E : Any, T : Collection<E>> T?.withNotNullNorEmpty(func: T.() -> Unit): Otherwise { 
    return if (this != null && this.isNotEmpty()) { 
     with (this) { func() } 
     OtherwiseIgnore 
    } else { 
     OtherwiseInvoke 
    } 
} 

inline fun <E : Any, T : Collection<E>> T?.whenNotNullNorEmpty(func: (T) -> Unit): Otherwise { 
    return if (this != null && this.isNotEmpty()) { 
     func(this) 
     OtherwiseIgnore 
    } else { 
     OtherwiseInvoke 
    } 
} 

inline fun <E : Any, T : Collection<E>> T?.withNullOrEmpty(func:() -> Unit): OtherwiseWithValue<T> { 
    return if (this == null || this.isEmpty()) { 
     func() 
     OtherwiseWithValueIgnore<T>() 
    } else { 
     OtherwiseWithValueInvoke(this) 
    } 
} 

inline fun <E : Any, T : Collection<E>> T?.whenNullOrEmpty(func:() -> Unit): OtherwiseWhenValue<T> { 
    return if (this == null || this.isEmpty()) { 
     func() 
     OtherwiseWhenValueIgnore<T>() 
    } else { 
     OtherwiseWhenValueInvoke(this) 
    } 
} 

interface Otherwise { 
    fun otherwise(func:() -> Unit): Unit 
} 

object OtherwiseInvoke : Otherwise { 
    override fun otherwise(func:() -> Unit): Unit { 
     func() 
    } 
} 

object OtherwiseIgnore : Otherwise { 
    override fun otherwise(func:() -> Unit): Unit { 
    } 
} 

interface OtherwiseWithValue<T> { 
    fun otherwise(func: T.() -> Unit): Unit 
} 

class OtherwiseWithValueInvoke<T>(val value: T) : OtherwiseWithValue<T> { 
    override fun otherwise(func: T.() -> Unit): Unit { 
     with (value) { func() } 
    } 
} 

class OtherwiseWithValueIgnore<T> : OtherwiseWithValue<T> { 
    override fun otherwise(func: T.() -> Unit): Unit { 
    } 
} 

interface OtherwiseWhenValue<T> { 
    fun otherwise(func: (T) -> Unit): Unit 
} 

class OtherwiseWhenValueInvoke<T>(val value: T) : OtherwiseWhenValue<T> { 
    override fun otherwise(func: (T) -> Unit): Unit { 
     func(value) 
    } 
} 

class OtherwiseWhenValueIgnore<T> : OtherwiseWhenValue<T> { 
    override fun otherwise(func: (T) -> Unit): Unit { 
    } 
} 


class TestBrancher { 
    @Test fun testOne() { 
     // when NOT null or empty 

     emptyList<String>().whenNotNullNorEmpty { list -> 
      fail("should not branch here") 
     }.otherwise { 
      // sucess 
     } 

     nullList<String>().whenNotNullNorEmpty { list -> 
      fail("should not branch here") 
     }.otherwise { 
      // sucess 
     } 

     listOf("a", "b").whenNotNullNorEmpty { list -> 
      assertEquals(listOf("a", "b"), list) 
     }.otherwise { 
      fail("should not branch here") 
     } 

     // when YES null or empty 

     emptyList<String>().whenNullOrEmpty { 
      // sucess 
     }.otherwise { list -> 
      fail("should not branch here") 
     } 

     nullList<String>().whenNullOrEmpty { 
      // success 
     }.otherwise { 
      fail("should not branch here") 
     } 

     listOf("a", "b").whenNullOrEmpty { 
      fail("should not branch here") 
     }.otherwise { list -> 
      assertEquals(listOf("a", "b"), list) 
     } 

     // with NOT null or empty 

     emptyList<String>().withNotNullNorEmpty { 
      fail("should not branch here") 
     }.otherwise { 
      // sucess 
     } 

     nullList<String>().withNotNullNorEmpty { 
      fail("should not branch here") 
     }.otherwise { 
      // sucess 
     } 

     listOf("a", "b").withNotNullNorEmpty { 
      assertEquals(listOf("a", "b"), this) 
     }.otherwise { 
      fail("should not branch here") 
     } 

     // with YES null or empty 

     emptyList<String>().withNullOrEmpty { 
      // sucess 
     }.otherwise { 
      fail("should not branch here") 
     } 

     nullList<String>().withNullOrEmpty { 
      // success 
     }.otherwise { 
      fail("should not branch here") 
     } 

     listOf("a", "b").withNullOrEmpty { 
      fail("should not branch here") 
     }.otherwise { 
      assertEquals(listOf("a", "b"), this) 
     } 


    } 

    fun <T : Any> nullList(): List<T>? = null 
} 
1

Xem xét sử dụng ?.forEach nếu phù hợp

activities?.forEach { 
    doSmth(it) 
} 

Nếu bạn muốn chính xác hành vi mà bạn mô tả tôi nghĩ rằng biến thể của bạn đọc tốt hơn sau đó bất cứ điều gì khác ngắn gọn hơn tôi có thể nghĩ đến. (Tuy nhiên, đơn giản if nên đủ)

+0

bình thường Không giải thích được câu trả lời này "với một danh sách. –

-1

Trước hết tôi muốn tư vấn để thực hiện chức năng mở rộng, thêm vào câu trả lời @ mlatu, mà xử lý tình trạng else


public inline fun Map.forEachElse(operation: (Map.Entry) -> Unit, elseBlock:() -> Unit): Unit { 
     if (!empty) 
      for (element in this) operation(element) 
     else 
      elseBlock() 
    } 

Nhưng việc sử dụng là không quá xinh đẹp.

Trên thực tế bạn đang tìm kiếm một lẽ đơn nguyên

1

Bên cạnh những câu trả lời khác, bạn cũng có thể sử dụng toán tử an toàn gọi kết hợp với các phương pháp khuyến nông isNotEmpty(). Do cuộc gọi an toàn, giá trị trả lại thực tế là Boolean? có thể là true, false hoặc null.Để sử dụng các biểu hiện trong một khoản if hoặc when, bạn sẽ cần phải explictly kiểm tra nếu nó true:

when { 
    activities?.isNotEmpty() == true -> doSomething 
    else -> doSomethingElse 
} 

cú pháp thay thế sử dụng toán tử elvis:

when { 
    activities?.isNotEmpty() ?: false -> doSomething 
    else -> doSomethingElse 
} 
4

thử này! rất rõ ràng.

var array: List<String>? = null 
if (array.orEmpty().isEmpty()) { 
    // empty 
} else { 
    // not empty 
} 
+0

Thực ra rất thanh lịch! –

Các vấn đề liên quan