Operadores
Operadores aritméticos, de comparação, lógicos, de intervalo e de tipo.
Kotlin oferece uma rica variedade de operadores que tornam o código mais expressivo e conciso. Além dos operadores aritméticos básicos, a linguagem fornece operadores especiais para null safety, type checking, ranges e muito mais.
Operadores aritméticos
Os operadores aritméticos básicos funcionam como esperado:
val a = 10
val b = 3
println(a + b) // 13 - Adição
println(a - b) // 7 - Subtração
println(a * b) // 30 - Multiplicação
println(a / b) // 3 - Divisão
println(a % b) // 1 - Módulo (resto)
Exemplo completo:
fun main() {
val a = 10
val b = 3
println("$a + $b = ${a + b}") // 10 + 3 = 13
println("$a - $b = ${a - b}") // 10 - 3 = 7
println("$a * $b = ${a * b}") // 10 * 3 = 30
println("$a / $b = ${a / b}") // 10 / 3 = 3
println("$a % $b = ${a % b}") // 10 % 3 = 1
}
Operadores de atribuição compostos
Kotlin suporta operadores de atribuição compostos para operações mais concisas:
var x = 10
x += 5 // x = x + 5
x -= 3 // x = x - 3
x *= 2 // x = x * 2
x /= 4 // x = x / 4
x %= 3 // x = x % 3
Exemplo completo:
fun main() {
var x = 10
println("Valor inicial: $x") // 10
x += 5
println("Após += 5: $x") // 15
x -= 3
println("Após -= 3: $x") // 12
x *= 2
println("Após *= 2: $x") // 24
x /= 4
println("Após /= 4: $x") // 6
x %= 4
println("Após %= 4: $x") // 2
}
Operadores de comparação
Os operadores de comparação retornam valores booleanos:
val a = 5
val b = 10
println(a == b) // false - Igualdade
println(a != b) // true - Desigualdade
println(a < b) // true - Menor que
println(a > b) // false - Maior que
println(a <= b) // true - Menor ou igual
println(a >= b) // false - Maior ou igual
Para comparação referencial (verificar se são o mesmo objeto), use ===:
val person1 = Person("Gustavo", 25)
val person2 = Person("Gustavo", 25)
val person3 = person1
println(person1 == person2) // true (mesmo conteúdo se for data class)
println(person1 === person2) // false (objetos diferentes)
println(person1 === person3) // true (mesmo objeto)
Exemplo completo:
data class Person(val name: String, val age: Int)
fun main() {
val person1 = Person("Gustavo", 25)
val person2 = Person("Gustavo", 25)
val person3 = person1
// Comparação estrutural (conteúdo)
println(person1 == person2) // true
println(person1 != person2) // false
// Comparação referencial (mesma instância)
println(person1 === person2) // false
println(person1 === person3) // true
println(person1 !== person2) // true
}
Operadores lógicos
Operadores para combinar expressões booleanas:
val isAdult = true
val hasLicense = false
println(isAdult && hasLicense) // false - AND
println(isAdult || hasLicense) // true - OR
println(!hasLicense) // true - NOT
Exemplo completo:
data class Person(val name: String, val age: Int, val hasDriverLicense: Boolean)
fun main() {
val person = Person("Gustavo", 25, true)
val isAdult = person.age >= 18
val hasLicense = person.hasDriverLicense
val canDrive = isAdult && hasLicense
val needsAttention = !isAdult || !hasLicense
println("É adulto: $isAdult") // true
println("Tem habilitação: $hasLicense") // true
println("Pode dirigir: $canDrive") // true
println("Precisa de atenção: $needsAttention") // false
}
Operador in e !in
O operador in verifica se um valor está contido em uma coleção ou range:
val numbers = listOf(1, 2, 3, 4, 5)
println(3 in numbers) // true
println(10 !in numbers) // true
val range = 1..10
println(5 in range) // true
println(15 in range) // false
Também funciona com strings:
val text = "Kotlin Programming"
println("Kotlin" in text) // true
println("Java" !in text) // true
Exemplo completo:
data class Person(val name: String, val age: Int)
fun main() {
val team = listOf(
Person("Gustavo", 25),
Person("Maria", 30),
Person("Pedro", 22)
)
val ages = team.map { it.age }
// Verificando em coleções
println(25 in ages) // true
println(40 !in ages) // true
// Verificando em ranges
val ageRange = 18..65
val allWorkingAge = team.all { it.age in ageRange }
println("Todos em idade ativa: $allWorkingAge") // true
// Verificando em strings
val searchName = "Gustavo Freze"
println("Gustavo" in searchName) // true
println("Pedro" !in searchName) // true
}
Operadores is e !is (Type Checking)
Os operadores is e !is verificam o tipo de um objeto em runtime:
val value: Any = "Kotlin"
if (value is String) {
// Smart cast: value é automaticamente convertido para String aqui
println(value.length)
}
if (value !is Int) {
println("Não é um número inteiro")
}
Com smart cast, não é necessário fazer cast explícito após verificar o tipo:
fun processValue(value: Any) {
when (value) {
is String -> println("String de tamanho ${value.length}")
is Int -> println("Número: ${value * 2}")
is List<*> -> println("Lista com ${value.size} elementos")
else -> println("Tipo desconhecido")
}
}
Exemplo completo:
open class Person(val name: String)
class Employee(name: String, val id: Int) : Person(name)
class Customer(name: String, val loyaltyPoints: Int) : Person(name)
fun processPerson(person: Person) {
when (person) {
is Employee -> {
// Smart cast para Employee
println("Funcionário: ${person.name}, ID: ${person.id}")
}
is Customer -> {
// Smart cast para Customer
println("Cliente: ${person.name}, Pontos: ${person.loyaltyPoints}")
}
else -> {
println("Pessoa: ${person.name}")
}
}
}
fun main() {
val people = listOf(
Person("Gustavo"),
Employee("Maria", 123),
Customer("Pedro", 500)
)
for (person in people) {
processPerson(person)
// Verificação de tipo
if (person is Employee) {
println(" -> É um funcionário")
}
if (person !is Customer) { // CORRECTED: !is without space
println(" -> Não é um cliente")
}
}
}
Operador as e as? (Type Casting)
O operador as realiza cast explícito, enquanto as? realiza safe cast (retorna null se o cast falhar):
val value: Any = "Kotlin"
// Cast inseguro - lança exception se falhar
val text = value as String
// Safe cast - retorna null se falhar
val number = value as? Int // null
val string = value as? String // "Kotlin"
Exemplo completo:
open class Person(val name: String)
class Employee(name: String, val id: Int) : Person(name)
fun main() {
val person: Person = Employee("Gustavo", 123)
val anyValue: Any = person
// Cast seguro
val employee = person as? Employee
if (employee != null) {
println("Funcionário ID: ${employee.id}")
}
// Cast inseguro (funciona porque person é realmente Employee)
val emp = person as Employee
println("ID: ${emp.id}")
// Safe cast que retorna null
val customer = person as? Customer
println("É cliente? ${customer != null}") // false
// Usando com Elvis operator
val id = (anyValue as? Employee)?.id ?: -1
println("ID do funcionário: $id")
}
// Classe auxiliar para o exemplo
class Customer(name: String) : Person(name)
Operador range (..)
O operador .. cria ranges, muito úteis em loops e verificações:
val range = 1..10 // Range fechado: 1 até 10 (inclusive)
val exclusive = 1 until 10 // Range semi-aberto: 1 até 9
val downTo = 10 downTo 1 // Range decrescente: 10 até 1
val stepped = 1..10 step 2 // Range com passo: 1, 3, 5, 7, 9
Ranges também funcionam com caracteres:
val letters = 'a'..'z'
println('k' in letters) // true
Exemplo completo:
data class Person(val name: String, val age: Int)
fun main() {
val people = listOf(
Person("Ana", 17),
Person("Bruno", 25),
Person("Carlos", 30),
Person("Diana", 45),
Person("Eduardo", 70)
)
// Definindo ranges de idade
val children = 0..17
val youngAdults = 18..30
val adults = 31..60
val seniors = 61..120
// Categorizando pessoas
people.forEach { person ->
val category = when (person.age) {
in children -> "Criança/Adolescente"
in youngAdults -> "Jovem Adulto"
in adults -> "Adulto"
in seniors -> "Idoso"
else -> "Idade inválida"
}
println("${person.name} (${person.age} anos): $category")
}
// Usando ranges em loops
println("\nContagem de 5 em 5:")
for (i in 0..20 step 5) {
print("$i ")
}
println("\n\nContagem regressiva:")
for (i in 5 downTo 1) {
print("$i ")
}
println("🚀")
}
Operador Elvis (?:)
O operador Elvis fornece um valor padrão, quando a expressão à esquerda é null:
val name: String? = null
val displayName = name ?: "Anônimo" // "Anônimo"
Muito útil com funções que retornam null:
fun findPerson(id: Int): Person? = // ... busca pessoa
val person = findPerson(123) ?: Person("Default", 0)
Exemplo completo:
data class Person(val name: String, val age: Int, val email: String? = null)
class PersonService {
private val people = mutableListOf(
Person("Gustavo", 25, "gustavo@email.com"),
Person("Maria", 30),
Person("Pedro", 22, "pedro@email.com")
)
fun findByName(name: String): Person? {
return people.find { it.name == name }
}
fun getEmail(name: String): String {
val person = findByName(name)
return person?.email ?: "noemail@default.com"
}
}
fun main() {
val service = PersonService()
// Usando Elvis com funções que retornam null
val person1 = service.findByName("Gustavo") ?: Person("Não encontrado", 0)
println(person1)
val person2 = service.findByName("Carlos") ?: Person("Não encontrado", 0)
println(person2)
// Usando Elvis para valores default
println("Email de Gustavo: ${service.getEmail("Gustavo")}")
println("Email de Maria: ${service.getEmail("Maria")}")
println("Email de Carlos: ${service.getEmail("Carlos")}")
// Encadeando Elvis operators
val config: String? = null
val backup: String? = null
val finalValue = config ?: backup ?: "valor padrão"
println("Configuração final: $finalValue")
}
Operador de Spread (*)
O operador spread (*) expande um array em argumentos individuais:
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
val array = intArrayOf(1, 2, 3)
val result = sum(*array) // Expande o array
Exemplo completo:
data class Person(val name: String, val skills: List<String>)
fun createTeam(leader: String, vararg members: String): List<String> {
return listOf(leader) + members
}
fun announceSkills(person: String, vararg skills: String) {
println("$person possui as seguintes habilidades:")
skills.forEach { println(" - $it") }
}
fun main() {
// Usando spread com arrays
val newMembers = arrayOf("Ana", "Bruno", "Carlos")
val team = createTeam("Gustavo", *newMembers)
println("Time: $team")
// Usando spread com arrays tipados
val numbers = intArrayOf(10, 20, 30, 40, 50)
val moreNumbers = intArrayOf(60, 70)
// Combinando arrays com spread
val allNumbers = intArrayOf(1, 2, *numbers, 99, *moreNumbers, 100)
println("Todos os números: ${allNumbers.toList()}")
// Usando spread com listas convertidas
val person = Person(
"Gustavo",
listOf("Kotlin", "Java", "Spring", "SQL")
)
announceSkills(person.name, *person.skills.toTypedArray())
}
Precedência de Operadores
A precedência determina a ordem de avaliação dos operadores:
- Postfix:
++,--,.,?.,? - Prefix:
-,+,++,--,! - Type:
:,as,as? - Multiplicativo:
*,/,% - Aditivo:
+,- - Range:
.. - Infix functions
- Elvis:
?: - Checks:
in,!in,is,!is - Comparação:
<,>,<=,>= - Igualdade:
==,!=,===,!== - Conjunction:
&& - Disjunction:
|| - Assignment:
=,+=,-=,*=,/=,%=
Exemplo completo:
fun main() {
// Precedência em ação
val result1 = 2 + 3 * 4 // 14, não 20 (multiplicação primeiro)
println("2 + 3 * 4 = $result1")
val result2 = (2 + 3) * 4 // 20 (parênteses forçam ordem)
println("(2 + 3) * 4 = $result2")
// Precedência com operadores lógicos
val a = true
val b = false
val c = true
val result3 = a || b && c // true (AND tem precedência sobre OR)
val result4 = (a || b) && c // true (parênteses mudam a ordem)
println("true || false && true = $result3")
println("(true || false) && true = $result4")
// Precedência com Elvis e comparação
val number: Int? = null
val result5 = number ?: 10 > 5 // true (?: tem menor precedência)
val result6 = (number ?: 10) > 5 // true (mais claro com parênteses)
println("null ?: 10 > 5 = $result5")
println("(null ?: 10) > 5 = $result6")
}