Question
In Kotlin, is there a clean way to use let with multiple nullable variables at the same time?
For example:
fun example(first: String?, second: String?) {
first?.let {
second?.let {
// Do something only if both are not null
}
}
}
I am looking for a shorter or clearer approach, something conceptually like this:
fun example(first: String?, second: String?) {
first?.let && second?.let {
// Do something only if both are not null
}
}
Is there an idiomatic Kotlin way to run code only when multiple nullable values are all non-null?
Short Answer
By the end of this page, you will understand how Kotlin's null-safety works with multiple nullable values, how let behaves, and the common idiomatic ways to execute code only when several variables are not null. You will also see practical alternatives such as if checks, nested let, early returns, and helper patterns.
Concept
Kotlin has built-in null-safety features to help prevent NullPointerException. A nullable type is written with ?, such as String?, which means the variable may contain either a String or null.
The let function is often used with the safe-call operator ?.:
value?.let {
// runs only if value is not null
}
This is useful for a single nullable value. But when you have multiple nullable variables, Kotlin does not provide special syntax like:
first?.let && second?.let { ... }
That syntax does not exist because let is just a normal function call on a value, not a language-level boolean operator.
When you want to run code only if several values are non-null, the main idea is simple:
- check that all required values are not null
- then use them in a non-null context
In Kotlin, the most common ways to do that are:
- nested
let - a normal
ifnull check - early return with guard clauses
Mental Model
Think of nullable values as keys that may or may not exist.
first?.let { ... }means: "If keyfirstexists, unlock this block."second?.let { ... }means the same forsecond.
If you need both keys, then both must be present before you can open the door.
You can do that in different ways:
- check one key, then the other
- check both first with an
if - return early if one key is missing
So the real question is not "How do I chain lets with &&?" but rather:
What is the clearest way to guarantee all required values are non-null before running the code?
Syntax and Examples
The simplest valid approaches in Kotlin are below.
1. Nested let
fun example(first: String?, second: String?) {
first?.let { f ->
second?.let { s ->
println("Both values exist: $f and $s")
}
}
}
This works, but nesting can become harder to read if you have many nullable values.
2. Use if to check both values
fun example(first: String?, second: String?) {
if (first != null && second != null) {
println("Both values exist: $first and $second")
}
}
This is often the clearest option. Inside the if block, Kotlin smart-casts both values to non-null.
3. Early return with guard clauses
fun {
(first == || second == )
println()
}
Step by Step Execution
Consider this example:
fun example(first: String?, second: String?) {
if (first != null && second != null) {
println(first.uppercase())
println(second.uppercase())
}
}
Now imagine this call:
example("hello", "world")
Step by step
firstreceives"hello".secondreceives"world".- Kotlin checks
first != null.- This is
true.
- This is
- Kotlin checks
second != null.- This is also
true.
- This is also
- Since both are true, the
ifblock runs. - Inside the block, Kotlin smart-casts both variables to non-null
String.
Real World Use Cases
This pattern appears often in everyday Kotlin code.
Form validation
if (email != null && password != null) {
login(email, password)
}
Only proceed when the required fields exist.
API response handling
if (user.id != null && user.name != null) {
saveUser(user.id, user.name)
}
Some API fields may be optional, so you check before using them.
Database values
if (row.title != null && row.createdAt != null) {
println("${row.title} created at ${row.createdAt}")
}
Useful when reading partially populated records.
Configuration loading
if (host != null && port != null) {
connect(host, port)
}
A program may need multiple configuration values before it can continue.
UI logic
(selectedUser != && selectedAccount != ) {
showDetails(selectedUser, selectedAccount)
}
Real Codebase Usage
In real projects, developers usually choose the style that makes the intent easiest to read.
Common pattern: guard clauses
fun process(first: String?, second: String?) {
if (first == null || second == null) return
println("Processing $first and $second")
}
Why it is popular:
- avoids deep nesting
- keeps the main logic at the left margin
- makes missing data handling explicit
Common pattern: validation before work
fun createUser(name: String?, email: String?) {
require(name != null && email != null) { "Name and email are required" }
println("Creating user: $name, $email")
}
This is useful when null values are considered invalid input.
Common pattern: helper for repeated null checks
: R? {
(a != && b != ) block(a, b)
}
Common Mistakes
1. Expecting special syntax for multiple let calls
Broken idea:
fun example(first: String?, second: String?) {
first?.let && second?.let {
println("Won't compile")
}
}
Why it fails:
letis not a boolean expression by itself&&works with boolean values, not function calls in this form
2. Using nested it and losing track of values
Confusing code:
fun example(first: String?, second: String?) {
first?.let {
second?.let {
println(it)
}
}
}
Problem:
- the inner
ithides the outerit - it becomes unclear which value you are using
Better:
{
first?.let { f ->
second?.let { s ->
println()
}
}
}
Comparisons
| Approach | Example | Best for | Pros | Cons |
|---|---|---|---|---|
Nested let | first?.let { f -> second?.let { s -> ... } } | Short nullable chains | Safe and expressive | Can become deeply nested |
if null check | if (first != null && second != null) { ... } | Most common cases | Very clear, smart-cast works | Slightly more verbose |
| Guard clause | `if (first == null | second == null) return` | Functions that should stop early | |
| Helper function | ifNotNull(first, second) { f, s -> ... } |
Cheat Sheet
Quick syntax
One nullable value
value?.let { nonNullValue ->
println(nonNullValue)
}
Two nullable values with if
if (first != null && second != null) {
doSomething(first, second)
}
Two nullable values with early return
if (first == null || second == null) return
doSomething(first, second)
Two nullable values with nested let
first?.let { f ->
second?.let { s ->
doSomething(f, s)
}
}
Rules to remember
?.calls something only if the value is not null.letis a scope function, not special null-check syntax.- There is no Kotlin syntax like
first?.let && second?.let. - For multiple nullable values,
ifis often the clearest choice. - Prefer named lambda parameters over nested .
FAQ
Can Kotlin use one let for two nullable variables?
Not directly with special syntax. You usually use nested let, an if check, or a helper function.
What is the most idiomatic way to check two nullable values in Kotlin?
In many cases, a simple if (a != null && b != null) is the clearest and most idiomatic choice.
Is nested let bad in Kotlin?
No, but too much nesting can hurt readability. For two or more variables, if or guard clauses are often easier to read.
Why does first?.let && second?.let not work?
Because let is a function call, not a boolean operator. The && operator only combines boolean expressions.
Should I use !! after checking for null?
Usually no. If Kotlin smart-casts the variables inside the checked block, !! is unnecessary.
How do I avoid deeply nested nullable code?
Use guard clauses, local variables, or helper functions to keep the code flat and readable.
Can I write a helper for multiple non-null values?
Yes. Many developers create small utility functions such as when the pattern appears often.
Mini Project
Description
Build a small Kotlin function that formats a contact card only when all required nullable inputs are available. This demonstrates how to safely combine multiple nullable values without using unsafe operators.
Goal
Create a function that prints a contact summary only when name and email are both non-null.
Requirements
- Write a function that accepts
name: String?andemail: String?. - Return early if either value is null.
- Print a formatted contact summary when both values exist.
- Call the function with both valid and null inputs to verify the behavior.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.