☔ Fluent Kotlin expressions for handling single if-else statements, nullable, collections, and boolean. This library supports Kotlin Multiplatform.
☔ WhatIf has been downloaded in more than 300k Kotlin and Android projects all over the world!
Add the dependency below to your module's build.gradle
file:
dependencies {
implementation("com.github.skydoves:whatif:1.2.1")
}
For Kotlin Multiplatform, add the dependency below to your module's build.gradle.kts
file:
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.github.skydoves:whatif:1.2.1")
}
}
}
WhatIf fully supports Kotlin Multiplatform, making it versatile for use in pure Kotlin modules as well as other platforms. You can leverage it in various use cases, including Jetpack Compose, where it helps streamline conditional logic. For instance, you can integrate WhatIf
in Jetpack Compose to handle conditional rendering, as shown in the example below. This flexibility allows developers to maintain clean, readable code across different Kotlin Multiplatform projects.
Box(
modifier = Modifier
.align(Alignment.Center)
.clickable { isBlueColor = !isBlueColor }
.whatIfMap(isBlueColor, { it.background(Color.Blue) }, { it.background(Color.Cyan) })
.whatIfMap(isBlueColor, { it.size(120.dp) }, { it.size(240.dp) }),
)
WhatIf
is a Kotlin expression that triggers a lambda expression (whatIf
block) when the provided boolean condition is true and the object is non-null. It's a concise way to handle conditional logic without needing verbose if-else statements, enabling cleaner, more readable code for specific actions when conditions are met.
val nullableBoolean: Boolean? = true
whatIf(nullableBoolean) {
log("not-null and true : $nullableBoolean")
}
Here is an extension for nullable booleans.
nullableBoolean.whatIf {
log("not-null and true : $nullableBoolean")
}
The whatIf
expression consists of three main parts: given
, whatIf
, and whatIfNot
. If the condition is true and the target is non-null, the whatIf
lambda is executed. However, if the condition is false or the target is null, the whatIfNot
lambda will be invoked instead. The whatIfNot
block is optional, so if there's no need to handle the false/null case, it can simply be omitted, allowing for more concise code when necessary.
whatIf(
given = nullableBoolean,
whatIf = { log("not-null and true : $nullableBoolean") },
whatIfNot = { log("null or false : $nullableBoolean") }
)
Here's an extension function designed specifically for nullable booleans.
nullableBoolean.whatIf(
whatIf = { log("not-null and true : $nullableBoolean") },
whatIfNot = { log("not-null or false : $nullableBoolean") }
)
Sometimes, you need to configure a builder differently depending on the available options. This is where WhatIf
proves useful, especially when using a chaining function like in builder patterns. It can be seamlessly applied to various builder patterns, such as AlertDialog.Builder
or any other similar construct, allowing conditional logic to be injected cleanly and fluently based on the provided conditions, without breaking the flow of method chaining.
val balloon = Balloon.Builder(baseContext)
.setArrowSize(10)
.setArrowVisible(true)
.whatIf(nullableBoolean) { setTextColor(Color.YELLOW) }
.whatIf(nullableBoolean, { setText("Hello, whatIf") }, { setText("Good-Bye whatIf") })
.setWidthRatio(1.0f)
.build()
WhatIfNotNull
is a Kotlin expression that triggers the whatIf
lambda when the target object is not null. This function simplifies handling nullable objects, allowing you to perform actions only when the object is valid, making your code cleaner by avoiding manual null checks. It's particularly useful for eliminating boilerplate when working with nullable types in Kotlin.
val nullableObject: Person? = Person()
nullableObject.whatIfNotNull {
log("$it is not null")
}
You can also handle cases where the target object is null. In such scenarios, instead of executing the whatIf
lambda, the whatIfNot
lambda will be triggered. This ensures that null cases are properly managed, providing an alternative action when the object is null, making your code more robust and adaptable to nullable conditions.
nullableObject.whatIfNotNull(
whatIf = { log("$it is not null.") },
whatIfNot = { log("$it is null.") }
)
WhatIfNotNullAs
is an expression for invoking whatIf
lambda when the target object is not null and the target can be cast by the desired type, the receiver will get a casted type.
- (serializable as? Poster?)?.let { poster ->
-
- }
+ parcelable.whatIfNotNullAs<Poster> { poster ->
+ log(poster.name)
+ }
You can also handle the exception case (target is null or can't cast by the desired type) using whatIfNot
.
- (serializable as? Poster?)?.let { poster ->
- log(poster.name)
- } ?: let {
- // do something
- }
+ serializable.whatIfNotNullAs<Poster>(
+ whatIf = { poster -> log(poster.name) },
+ whatIfNot = {
+ // do something
+ })
An expression for invoking the whatIf
lambda when the target, such as a string, collection, or array, is neither null nor empty. If the target is null or empty, the whatIfNot
lambda will be executed instead. This approach ensures that you can easily handle non-empty, valid collections or arrays, while providing an alternative behavior for null or empty cases, streamlining conditional logic when dealing with these data types.
val nullableString: String? = "NotNullOrEmpty"
nullableString.whatIfNotNullOrEmpty {
log("$it is not null and not empty")
}
Here is an example for collections.
nullableList.whatIfNotNullOrEmpty {
log("list $it is not null and not empty")
}
You can also handle the null or empty case.
nullableList.whatIfNotNullOrEmpty(
whatIf = { log("list $it is not null and not empty") },
whatIfNot = { log("list is null or empty") }
)
Here is the same example for the array.
nullableArray.whatIfNotNullOrEmpty {
log("$it is not null and not empty")
}
Array, ByteArray, ShortArray, IntArray, LongArray, FloatArray, DoubleArray, BooleanArray, CharArray
You can use some expressions for List, Map, and Set.
- whatIfNotNullOrEmpty: An expression for invoking
whatIf
when theList
is not null and not empty. - addWhatIfNotNull: An expression for adding an element and invoking
whatIf
when the element is not null. - addAllWhatIfNotNull: An expression for adding an element and invoking
whatIf
when the element is not null. - removeWhatIfNotNull: An expression for removing an element and invoking
whatIf
when the element is not null. - removeAllWhatIfNotNull: An expression for removing a collection of element and invoking
whatIf
when the element is not null.
The basic concept is the same as whatIf
. An expression for invoking whatIf
when the target object is not null. It is useful when the type of the receiver and the result should be different.
val length: Int = nullableString.whatIfMap(
whatIf = { it.length },
whatIfNot = {
log("$it, nullableString is null.")
-1
}
)
You can use a default value instead of the whatIfNot
and it can be omitted.
val length = nullableString.whatIfMap(
default = -1
) {
log("$it, length can not over than 5.")
5
}
An expression for invoking whatIf
lambda when the target boolean is not null and false.
nullableBoolean.whatIfElse {
log("nullableBoolean is not null and false")
}
An expression for invoking whatIf
lambda when the target boolean is true and/or a predicate receiver is true.
nullableBoolean.whatIfAnd(predicate) {
log("nullableBoolean is true and the predicate is also true")
}
nullableBoolean.whatIfOr(predicate) {
log("nullableBoolean is true or the predicate is true")
}
You can use the whatIf extensions related to the Android project.
Add the dependency below to your module's build.gradle
file:
dependencies {
implementation "com.github.skydoves:whatif-android-ext:version"
}
An expression for invoking whatIf
lambda when the Activity's intent extras is not null and not empty.
var foo: String? = null
this@MainActivity.whatIfHasExtras {
foo = "${it.getString("foo")}"
}
You can also handle the null case.
this@MainActivity.whatIfHasExtras(
whatIf = { foo = "${it.getString("foo")}" },
whatIfNot = { log("intent extras is null or empty.") }
)
You can null-check and typecast simultaneously when you getting intent extra data.
whatIfHasSerializableExtra<Poster>("poster") { poster ->
...
}
whatIfHasParcelableExtra<Poster>("poster") { poster ->
...
}
An expression for invoking whatIf
lambda when the Context is not null.
class WhatIfFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
whatIfNotNullContext {
Toast.makeText(it, "context is not null!", Toast.LENGTH_SHORT).show()
}
}
}
An expression for invoking whatIf
when the Fragment.getArguments
is not null.
whatIfNotNullArguments {
it.getString("name").whatIfNotNull {
log("my name is $it")
}
}
An expression for invoking whatIf
lambda when the Activity is not null.
whatIfNotNullActivity { activity ->
activity.supportFragmentManager.addOnBackStackChangedListener {
// .. //
}
}
An expression for invoking whatIf
lambe when the Fragment
has an T
interface as a parent. Let's assume we have a MainActivity
that implements OnClickCallback
interface,
class MainActivity : AppCompatActivity(), OnClickCallback {
...
}
You can get the parent Activity's OnClickCallback
interface on Fragment as following with the whatIfFindParentInterface
:
class MainFragment: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
whatIfFindParentInterface<OnClickCallback> {
it.onClickedButtonFromFragment()
}
}
}
Support it by joining stargazers for this repository. ⭐
Also, follow me for my next creations! 🤩
Copyright 2019 skydoves (Jaewoong Eum)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.