2017-05-23 59 views
8

Mam właściwość zerowalną (obiekt Java), która wie, jak konwertować się na ciąg znaków, a jeśli ta reprezentacja nie jest pusta, chciałabym zrób coś z tym. W Javie to wygląda:Idiom Kotlina do pracy z obiektem niezerowym i niepustą Reprezentacja ciągów znaków

MyObject obj = ... 
if (obj != null) { 
    String representation = obj.toString(); 
    if (!StringUtils.isBlank(representation)) { 
     doSomethingWith(representation); 
    } 
} 

Próbuję znaleźć najbardziej idiomatyczne sposób konwertowania to Kotlin i mam:

with(obj?.toString()) { 
     if (!isNullOrBlank()) { 
      doSomethingWith(representation) 
     } 
    } 

Ale to nadal czuje się zbyt dużo pracy dla takiego prosta operacja. Mam przeczucie, że łącząc to, mogę nieco to skrócić.

Kroki są:

  1. Jeśli obiekt (A) nie jest null
  2. Jeśli reprezentacja String (B) przedmiotu (A) nie jest puste
  3. coś z (B)

próbowałem:

when(where?.toString()) { 
     isNullOrBlank() -> builder.append(this) 
    } 

Ale (1) nie jest on z:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: @InlineOnly public inline fun 
CharSequence?.isNullOrBlank(): Boolean defined in kotlin.text @InlineOnly public inline fun CharSequence?.isNullOrBlank(): Boolean defined in 
kotlin.text 

A nawet jeśli to ma przeszłość, (2) że to chcesz wyczerpujący else, które nie troszczą się dołączyć.

Co to jest "droga Kotlina"?

Odpowiedz

9

można użyć (od Kotlin 1.1) wbudowany w stdlib takeIf() lub takeUnless rozszerzeń, albo działa:

obj?.toString().takeUnless { it.isNullOrBlank() }?.let { doSomethingWith(it) } 

// or 

obj?.toString()?.takeIf { it.isNotBlank() }?.let { doSomethingWith(it) } 

// or use a function reference 

obj?.toString().takeUnless { it.isNullOrBlank() }?.let(::doSomethingWith) 

Za wykonanie czynności doSomethingWith() na wartości końcowej, można użyć apply() do działa w kontekście bieżącego obiektu, a powrót to ten sam obiekt, lub let(), aby zmienić wynik wyrażenia, lub run(), aby działał w kontekście bieżącego obiektu, a także zmienić wynik wyrażenia, lub also() na kod ecute podczas zwracania oryginalnego obiektu.

Można również utworzyć własną funkcję przedłużacza jeśli chcesz nazewnictwo być bardziej sensowne, na przykład nullIfBlank() może być dobrym nazwa:

obj?.toString().nullIfBlank()?.also { doSomethingWith(it) } 

który jest zdefiniowany jako rozszerzenie do wartości pustych String:

fun String?.nullIfBlank(): String? = if (isNullOrBlank()) null else this 

Jeśli dodamy jeszcze jedno rozszerzenie:

fun <R> String.whenNotNullOrBlank(block: (String)->R): R? = this.nullIfBlank()?.let(block) 

Pozwala kod należy uprościć:

obj?.toString()?.whenNotNullOrBlank { doSomethingWith(it) } 

// or with a function reference 

obj?.toString()?.whenNotNullOrBlank(::doSomethingWith) 

Zawsze można napisać rozszerzenia jak to poprawić czytelność kodu.

Uwaga: Czasami użyłem bezpiecznego dostępu null dla ?., a innym razem nie. Dzieje się tak dlatego, że predykaty/lambdy niektórych funkcji działają z wartościami pustymi, a inne nie. Możesz zaprojektować je w dowolny sposób. To zależy od Ciebie!

Aby uzyskać więcej informacji na ten temat patrz: Idiomatic way to deal with nullables

+2

dobra odpowiedź, ale myślę, że po włączeniu testu IF-tu. Chce wywołać 'doSomethingWith', jeśli reprezentacja łańcuchów ma wartość _not_ null. – marstran

+0

Ach ok, odwróci moją odpowiedź :-) dzięki –

+0

@marstran Prawidłowo - chcę tylko _do rzeczy, jeśli mam dobrą reprezentację String. (Dobro jest niezerowe i niepuste.) –