Đố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 Optional
và Maybe
.
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ở this
và whenXyz
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
}
Lưu ý: 'khi' có hai lựa chọn thay thế rất gần với' if' –