Für einige einfache Aktionen Monade, die Aktion unter der Annahme, auch respektiert nicht in Betrieb ist auf eine leere Liste (Ihr Fall von beide null und zu handhaben leer:
myList?.forEach { ...only iterates if not null and not empty }
Für andere Aktionen, die Sie eine Erweiterungsfunktion schreiben können - zwei Varianten, je nachdem, ob Sie die Liste als this
oder als Parameter erhalten.
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)
}
}
Welche können Sie verwenden, wie:
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`
}
}
Sie auch inverse Funktion tun können:
inline fun <E: Any, T: Collection<E>> T?.withNullOrEmpty(func:() -> Unit): Unit {
if (this == null || this.isEmpty()) {
func()
}
}
ich diese Verkettungs vermeiden würde, weil dann ersetzen Sie eine if
oder when
Aussage mit etwas mehr wortreich. Und Sie kommen mehr in den Bereich, den die Alternativen, die ich unten erwähne, liefern, die für Erfolg/Misserfolg-Situationen voll verzweigen.
Hinweis: Diese Erweiterungen wurden für alle Nachkommen von Collections
mit Nicht-Null-Werten verallgemeinert. Und arbeite für mehr als nur Listen.
Alternativen:
Die Result Bibliothek für Kotlin eine schöne Art und Weise gibt Ihren Fall von „dies tun, oder dass“ zu handhaben, basierend auf Antwortwert. Für Promises finden Sie dasselbe in der Bibliothek Kovenant.
Diese beiden Bibliotheken geben Ihnen die Möglichkeit, alternative Ergebnisse von einer einzelnen Funktion zurückzugeben und den Code basierend auf den Ergebnissen zu verzweigen. Sie erfordern, dass Sie den Anbieter der "Antwort" steuern, die bearbeitet wird.
Dies sind gute Kotlin Alternativen zu Optional
und Maybe
.
Erforschung der Erweiterungsfunktionen Weitere (und vielleicht zu viel)
Dieser Abschnitt ist nur um zu zeigen, dass, wenn Sie ein Problem betroffen wie die Frage hier aufgeworfenen, Sie leicht viele Antworten in Kotlin finden zu machen so programmieren, wie Sie es wollen. Wenn die Welt nicht sympathisch ist, ändere die Welt. Es ist nicht als gute oder schlechte Antwort gedacht, sondern eher als zusätzliche Information.
Wenn Sie die Erweiterungsfunktionen mögen und prüfen wollen, dass sie in einem Ausdruck verketten, würde ich wahrscheinlich sie wie folgt ändern ...
Die withXyz
Aromen this
zurückzukehren und die whenXyz
sollte eine neue Art Rückkehr erlaubt die ganze Sammlung wird zu einer neuen (vielleicht sogar ohne Bezug zum Original). Resultierende in Code wie folgt aus:
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")
}
}
Hinweis: Die vollständige Code für diese Version ist am Ende des Pfostens (1)
Aber man konnte auch eine völlig neue Richtung mit einem benutzerdefinierten gehen " dies sonst, dass“Mechanismus:
fun foo(someList: List<String>?) {
someList.whenNullOrEmpty {
// other code
}
.otherwise { list ->
// do something with `list`
}
}
keine Grenzen gesetzt sind, kreativ sein und die Kraft der Erweiterungen lernen, neue Ideen auszuprobieren, und wie Sie gibt es viele Variationen sehen, wie die Menschen wollen diese Art von Situationen codieren . Die stdlib kann 8 Variationen dieser Art von Methoden nicht unterstützen, ohne zu verwirren. Jede Entwicklungsgruppe kann jedoch Erweiterungen haben, die ihrem Codierungsstil entsprechen.
Hinweis: Die vollständige Code für diese Version ist am Ende des Pfostens (2)
Beispielcode 1:Hier wird der vollständige Code für die "gekettet" Version ist:
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
}
Beispielcode 2:Hier ist der vollständige Code für einen „dies sonst dass“Bibliothek (mit Unit-Test):
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
}
Hinweis: a 'when' mit zwei Alternativen zu einem normalen sehr nahe' if' –