---
title: "Google Guava в примери"
url: "https://romankryvolapov.com/bg/google-guava-in-examples/"
description: "Възможностите на Google Guava в примери на Kotlin: Multimap, BiMap, Table, кеш, работа с низове, хеширане, IO и конкурентност."
language: bg
published: 2023-10-16
updated: 2026-11-13
---
Google Guava е библиотека с разширен набор от помощни инструменти за Java, която улеснява много аспекти от разработката. Тя предлага множество полезни класове и методи за работа с колекции, кеширане, функционално програмиране, обработка на низове и още много неща.

Основни възможности на Google Guava:

## Колекции

Guava значително разширява стандартните колекции на Java, като предоставя нови структури от данни и помощни инструменти за работа с тях.

**Multimap:**\
Колекция, която позволява да се съхраняват няколко стойности за един ключ.\
**Примери:** ArrayListMultimap, HashMultimap, LinkedListMultimap.

```kotlin
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap


fun multimapExample() {
    val multimap: Multimap<String, String> = ArrayListMultimap.create()
    multimap.put("fruit", "apple")
    multimap.put("fruit", "banana")
    multimap.put("vegetable", "carrot")
    println(multimap.get("fruit"))  // [apple, banana]
    println(multimap.get("vegetable"))  // [carrot]
}
```

**Multiset:**\
Колекция, която позволява да се съхраняват няколко копия на един и същ елемент.\
**Примери:** HashMultiset, TreeMultiset.

```kotlin
import com.google.common.collect.HashMultiset
import com.google.common.collect.Multiset


fun multisetExample() {
    val multiset: Multiset<String> = HashMultiset.create()
    multiset.add("apple")
    multiset.add("apple")
    multiset.add("banana")
    println(multiset.count("apple"))  // 2
    println(multiset.count("banana"))  // 1
}
```

**BiMap:**\
Двупосочна Map, в която на всеки ключ съответства уникална стойност и обратно.\
**Пример:** HashBiMap.

```kotlin
import com.google.common.collect.HashBiMap


fun bimapExample() {
    val biMap = HashBiMap.create<String, String>()
    biMap["one"] = "1"
    biMap["two"] = "2"
    // Достъп до стойност по ключ
    println(biMap["one"])  // 1
    // Обратен достъп до ключ по стойност
    println(biMap.inverse()["1"])  // one
}
```

**Table:**\
Двумерна Map, еквивалентна на `Map<R, Map<C, V>>`.\
**Пример:** HashBasedTable.

```kotlin
import com.google.common.collect.HashBasedTable
import com.google.common.collect.Table


fun tableExample() {
    val table: Table<String, String, Int> = HashBasedTable.create()
    table.put("row1", "column1", 1)
    table.put("row1", "column2", 2)
    table.put("row2", "column1", 3)
    println(table.get("row1", "column1"))  // 1
    println(table.get("row1", "column2"))  // 2
    println(table.row("row1"))  // {column1=1, column2=2}
    println(table.column("column1"))  // {row1=1, row2=3}
}
```

**ClassToInstanceMap:**\
Map, в която ключовете са класове, а стойностите са екземпляри на тези класове.\
**Пример:** MutableClassToInstanceMap.

```kotlin
import com.google.common.collect.MutableClassToInstanceMap
import com.google.common.collect.ClassToInstanceMap


fun classToInstanceMapExample() {
    val classToInstanceMap: ClassToInstanceMap<Any> = MutableClassToInstanceMap.create()
    classToInstanceMap.putInstance(String::class.java, "Hello World")
    classToInstanceMap.putInstance(Int::class.java, 42)
    val strValue = classToInstanceMap.getInstance(String::class.java)
    val intValue = classToInstanceMap.getInstance(Int::class.java)
    println(strValue)  // Hello World
    println(intValue)  // 42
}
```

**RangeSet:**\
Набор от числови диапазони, който предоставя операции за проверка на пресичане и включване.\
**Пример:** TreeRangeSet.

```kotlin
import com.google.common.collect.Range
import com.google.common.collect.TreeRangeSet


fun rangeSetExample() {
    val rangeSet = TreeRangeSet.create<Int>()
    rangeSet.add(Range.closed(1, 10))
    rangeSet.add(Range.closed(20, 30))
    println(rangeSet.contains(5))  // true
    println(rangeSet.contains(15))  // false
    println(rangeSet.contains(25))  // true
}
```

**RangeMap:**\
Map, чиито ключове са диапазони, а стойностите – обекти, свързани с тези диапазони.\
**Пример:** TreeRangeMap.

```kotlin
import com.google.common.collect.Range
import com.google.common.collect.TreeRangeMap


fun rangeMapExample() {
    val rangeMap = TreeRangeMap.create<Int, String>()
    rangeMap.put(Range.closed(1, 10), "Low")
    rangeMap.put(Range.closed(20, 30), "Medium")
    rangeMap.put(Range.closed(31, 40), "High")
    println(rangeMap.get(5))   // Low
    println(rangeMap.get(25))  // Medium
    println(rangeMap.get(35))  // High
}
```

**Immutable Collections:**\
Неизменяеми версии на стандартните колекции за по-голяма сигурност и оптимизация.\
**Примери:** ImmutableList, ImmutableSet, ImmutableMap, ImmutableMultimap, ImmutableTable.

```kotlin
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet


fun immutableCollectionsExample() {
    val immutableList: List<String> = ImmutableList.of("apple", "banana", "cherry")
    val immutableSet: Set<String> = ImmutableSet.of("apple", "banana", "cherry")
    println(immutableList)  // [apple, banana, cherry]
    println(immutableSet)  // [apple, banana, cherry]
    // Тези колекции са неизменяеми, опитът да се добави елемент предизвиква грешка
    // immutableList.add("pear")  // UnsupportedOperationException
}
```

## Работа с низове

**Splitter:**\
Помощен инструмент за разделяне на низ по разделител с различни опции (пропускане на празни низове, изрязване на интервали и т. н.).

```kotlin
import com.google.common.base.Splitter


fun splitterExample() {
    val input = "apple, banana, , orange,,"
    val result = Splitter.on(',')
        .trimResults() // Изрязваме интервалите
        .omitEmptyStrings() // Пропускаме празните низове
        .splitToList(input)
    println(result)  // [apple, banana, orange]
}
```

**Joiner:**\
Помощен инструмент за обединяване на колекция от низове или други обекти в низ с посочен разделител.

```kotlin
import com.google.common.base.Joiner


fun joinerExample() {
    val fruits = listOf("apple", null, "banana", "orange")
    // Joiner ще пропуска null стойностите
    val result = Joiner.on(", ")
        .skipNulls()
        .join(fruits)
    println(result)  // apple, banana, orange
}
```

**CharMatcher:**\
Помощен инструмент за търсене и манипулации със символи в низ.

```kotlin
import com.google.common.base.CharMatcher


fun charMatcherExample() {
    val input = "Hello123 World456"
    // Премахваме всички цифри
    val onlyLetters = CharMatcher.javaDigit().removeFrom(input)
    println(onlyLetters)  // Hello World
    // Оставяме само цифрите
    val onlyDigits = CharMatcher.javaDigit().retainFrom(input)
    println(onlyDigits)  // 123456
    // Изрязваме интервалите и ги заменяме със запетаи
    val trimmed = CharMatcher.whitespace().trimAndCollapseFrom(input, ',')
    println(trimmed)  // Hello123,World456
}
```

**CaseFormat:**\
Преобразуване между различни формати на регистъра на низовете (например snake_case, camelCase, UPPER_UNDERSCORE и др.).

```kotlin
import com.google.common.base.CaseFormat


fun caseFormatExample() {
    val input = "my_variable_name"
    // Преобразуваме от snake_case в camelCase
    val camelCase = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, input)
    println(camelCase)  // myVariableName
    // Преобразуваме от snake_case в UPPER_UNDERSCORE
    val upperUnderscore = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, input)
    println(upperUnderscore)  // MY_VARIABLE_NAME
}
```

## Кеширане

Guava предоставя мощен механизъм за кеширане чрез класовете Cache и LoadingCache, който поддържа различни стратегии за премахване на данни, като премахване по срок на живот или по брой елементи

**Cache:**\
Вградена имплементация на кеш с поддръжка на автоматично премахване на данни по срок на живот или по обем.

```kotlin
import com.google.common.cache.CacheBuilder
import com.google.common.cache.Cache


fun simpleCacheExample() {
    // Създаваме кеш с максимален брой елементи 100 и време на живот 10 минути
    val cache: Cache<String, String> = CacheBuilder.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(10, java.util.concurrent.TimeUnit.MINUTES)
        .build()
    // Добавяме данни в кеша
    cache.put("key1", "value1")
    // Получаваме данни от кеша
    val value = cache.getIfPresent("key1")
    println(value)  // value1
    // Ако ключът липсва, се връща null
    val missingValue = cache.getIfPresent("key2")
    println(missingValue)  // null
}
```

**LoadingCache:**\
Кеш, който автоматично зарежда данните, ако ги няма, с помощта на функция за зареждане.

```kotlin
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import com.google.common.cache.LoadingCache
import java.util.concurrent.TimeUnit


fun loadingCacheExample() {
    // Създаваме кеш, който автоматично зарежда данните, ако ги няма
    val loadingCache: LoadingCache<String, String> = CacheBuilder.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build(object : CacheLoader<String, String>() {
            override fun load(key: String): String {
                return "Generated value for $key"
            }
        })
    // Получаваме данни от кеша; ако ключът липсва – данните се генерират автоматично
    println(loadingCache.get("key1"))  // Generated value for key1
    // Добавяме елемент ръчно в кеша
    loadingCache.put("key2", "Manually added value")
    println(loadingCache.get("key2"))  // Manually added value
}
```

**RemovalListener:**\
Обработчик за събитията за премахване на елементи от кеша.

```kotlin
import com.google.common.cache.CacheBuilder
import com.google.common.cache.RemovalListener
import com.google.common.cache.RemovalNotification
import java.util.concurrent.TimeUnit


fun cacheWithRemovalListenerExample() {
    // Създаваме кеш с обработчик за премахване на елементи
    val cache = CacheBuilder.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .removalListener(object : RemovalListener<String, String> {
            override fun onRemoval(notification: RemovalNotification<String, String>) {
                println("Removed key: ${notification.key}, value: ${notification.value}, cause: ${notification.cause}")
            }
        })
        .build<String, String>()
    // Добавяме и премахваме елементи от кеша
    cache.put("key1", "value1")
    cache.invalidate("key1")  // Принудително премахване на елемент
}
```

**CacheBuilder:**\
Позволява гъвкаво да се настрои кешът с ограничения за времето на живот на елементите, техния брой, обработката на конкуренцията и т. н.

```kotlin
import com.google.common.cache.CacheBuilder
import com.google.common.cache.Cache


fun cacheBuilderExample() {
    // Създаваме кеш с максимален брой елементи и време на живот 5 минути
    val cache: Cache<String, String> = CacheBuilder.newBuilder()
        .maximumSize(200) // Ограничение по брой елементи
        .expireAfterWrite(5, TimeUnit.MINUTES) // Елементите живеят 5 минути
        .build()
    // Добавяме елемент
    cache.put("key1", "value1")
    // Получаваме елемента
    println(cache.getIfPresent("key1"))  // value1
    // След 5 минути елементът ще бъде премахнат автоматично
}
```

## Функционално програмиране

**Predicate:**\
Интерфейс за определяне на логическо условие за обекти.

```kotlin
import com.google.common.base.Predicate
import com.google.common.collect.FluentIterable


fun predicateExample() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    // Определяме предикат за филтриране на четните числа
    val isEven: Predicate<Int> = Predicate { it % 2 == 0 }
    // Използваме FluentIterable за филтриране на числата
    val evenNumbers = FluentIterable.from(numbers)
        .filter(isEven)
        .toList()
    println(evenNumbers)  // [2, 4, 6, 8, 10]
}
```

**Function:**\
Интерфейс за преобразуване на един обект в друг.

```kotlin
import com.google.common.base.Function
import com.google.common.collect.FluentIterable


fun functionExample() {
    val numbers = listOf(1, 2, 3, 4, 5)
    // Определяме функция за повдигане на число на квадрат
    val squareFunction: Function<Int, Int> = Function { it * it }
    // Преобразуваме списъка с числа
    val squaredNumbers = FluentIterable.from(numbers)
        .transform(squareFunction)
        .toList()
    println(squaredNumbers)  // [1, 4, 9, 16, 25]
}
```

**Suppliers:**\
Помощен инструмент за лениво и мемоизирано доставяне на стойности.

```kotlin
import com.google.common.base.Suppliers
import java.util.concurrent.TimeUnit


fun supplierExample() {
    // Лениво изчисляване на низ с мемоизация за 10 секунди
    val supplier = Suppliers.memoizeWithExpiration(
        Suppliers.ofInstance("Hello, world!"),
        10, TimeUnit.SECONDS
    )
    // Получаваме стойността
    println(supplier.get())  // Hello, world!
    // Стойността се кешира за 10 секунди, след което ще бъде преизчислена
}
```

**Optional:**\
Контейнер за обекти, който може или да съдържа стойност, или да е празен (алтернатива на null).

```kotlin
import com.google.common.base.Optional


fun optionalExample() {
    val optionalPresent: Optional<String> = Optional.of("Hello")
    val optionalAbsent: Optional<String> = Optional.absent()
    // Проверка за наличие на стойност
    if (optionalPresent.isPresent) {
        println(optionalPresent.get())  // Hello
    }
    // Връщане на стойност по подразбиране, ако няма такава
    println(optionalAbsent.or("Default Value"))  // Default Value
}
```

**FluentIterable:**\
Помощен инструмент за обработка на колекции с поддръжка на методи за функционална композиция (филтриране, преобразуване и т. н.).

```kotlin
import com.google.common.collect.FluentIterable


fun fluentIterableExample() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    // Комбинираме филтриране и трансформация с помощта на FluentIterable
    val processedNumbers = FluentIterable.from(numbers)
        .filter { it % 2 == 0 } // Филтрираме само четните числа
        .transform { it * 2 }  // Умножаваме всяко по 2
        .toList()
    println(processedNumbers)  // [4, 8, 12, 16, 20]
}
```

## Работа с изключения

**Throwables:**\
Помощни инструменти за работа с изключения (например преобразуване на checked изключения в runtime изключения).

```kotlin
import com.google.common.base.Throwables


fun throwablesExample() {
    try {
        // Изкуствено създаваме изключение
        throw IllegalArgumentException("Illegal argument!")
    } catch (e: Exception) {
        // Извеждаме пълната информация за изключението
        println(Throwables.getStackTraceAsString(e))
        // Проверка и повторно хвърляне на изключението, ако е от определен тип
        if (Throwables.getRootCause(e) is IllegalArgumentException) {
            throw Throwables.propagate(e)
        }
    }
}
```

**Retryer:**\
Помощен инструмент за повторно изпълнение на операции при възникване на изключения с поддръжка на стратегии за изчакване и спиране. Google Guava не съдържа вградена поддръжка на Retryer, но има популярни библиотеки, като Failsafe или Guava-Retrying, които могат да се използват за повторни опити. Ето пример за използване на библиотеката Guava-Retrying за повторен опит за изпълнение на операция:

```kotlin
import com.github.rholder.retry.Retryer
import com.github.rholder.retry.RetryerBuilder
import com.github.rholder.retry.StopStrategies
import com.github.rholder.retry.WaitStrategies
import java.util.concurrent.TimeUnit


fun retryerExample() {
    // Създаваме Retryer с максимален брой опити 3 и изчакване 2 секунди между опитите
    val retryer: Retryer<String> = RetryerBuilder.newBuilder<String>()
        .retryIfException() // Повтаряме при възникване на всяко изключение
        .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS)) // Изчакваме 2 секунди между опитите
        .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // Спираме след 3 опита
        .build()
    try {
        // Изпълняваме операцията с повторни опити
        val result = retryer.call {
            // Логика, която може да хвърли изключение
            if (Math.random() > 0.7) {
                "Success"
            } else {
                throw RuntimeException("Failed attempt")
            }
        }
        println("Operation succeeded: $result")
    } catch (e: Exception) {
        println("Operation failed after retries: ${e.message}")
    }
}
```

**Checked exceptions to Unchecked exceptions:**\
Guava помага при преобразуването на checked изключения в unchecked чрез Throwables.propagate():

```kotlin
import com.google.common.base.Throwables


fun propagateExample() {
    try {
        throwCheckedException()
    } catch (e: Exception) {
        // Преобразуваме checked изключението в unchecked изключение
        throw Throwables.propagate(e)
    }
}


fun throwCheckedException() {
    throw Exception("Checked exception!")
}
```

## Работа с примитиви

Google Guava предлага удобни помощни инструменти за работа с примитиви, като Ints, Longs, Doubles, Booleans, Bytes, както и поддръжка на цели числа без знак и на неизменяеми колекции за примитиви. Тези инструменти позволяват да се избегне работата с обвивките на примитивните типове и да се изпълняват различни операции по-ефективно.

**Ints, Longs, Doubles, Booleans, Floats, Bytes:**\
Помощни инструменти за преобразуване и работа с примитивни типове.

```kotlin
import com.google.common.primitives.Ints


fun intsExample() {
    val numbers = listOf(1, 2, 3, 4, 5)
    // Преобразуване на списък в масив от int
    val intArray = Ints.toArray(numbers)
    println(intArray.contentToString())  // [1, 2, 3, 4, 5]
    // Търсене на максималната и минималната стойност
    println(Ints.max(1, 3, 5, 2))  // 5
    println(Ints.min(1, 3, 5, 2))  // 1
    // Проверка за наличие на число в масива
    println(Ints.contains(intArray, 3))  // true
    // Сравнение на два int
    println(Ints.compare(5, 10))  // -1 (първият е по-малък от втория)
}
```

```kotlin
import com.google.common.primitives.Longs


fun longsExample() {
    val longArray = longArrayOf(10L, 20L, 30L)
    // Преобразуване на масив от long в списък
    val longList = Longs.asList(*longArray)
    println(longList)  // [10, 20, 30]
    // Преобразуване на списъка обратно в масив
    val array = Longs.toArray(longList)
    println(array.contentToString())  // [10, 20, 30]
}
```

```kotlin
import com.google.common.primitives.Doubles


fun doublesExample() {
    val doubleArray = doubleArrayOf(1.1, 2.2, 3.3)
    // Преобразуване на масив от double в списък
    val doubleList = Doubles.asList(*doubleArray)
    println(doubleList)  // [1.1, 2.2, 3.3]
    // Преобразуване на списъка обратно в масив
    val array = Doubles.toArray(doubleList)
    println(array.contentToString())  // [1.1, 2.2, 3.3]
    // Сравнение на два double
    println(Doubles.compare(3.14, 2.71))  // 1 (първият е по-голям от втория)
}
```

```kotlin
import com.google.common.primitives.Booleans

fun booleansExample() {
    val booleanArray = booleanArrayOf(true, false, true)
    // Преобразуване на масив от boolean в списък
    val booleanList = Booleans.asList(*booleanArray)
    println(booleanList)  // [true, false, true]
    // Преобразуване на списъка обратно в масив
    val array = Booleans.toArray(booleanList)
    println(array.contentToString())  // [true, false, true]
}
```

```kotlin
import com.google.common.primitives.Bytes


fun bytesExample() {
    val byteArray = byteArrayOf(1, 2, 3)
    // Преобразуване на масив от byte в списък
    val byteList = Bytes.asList(*byteArray)
    println(byteList)  // [1, 2, 3]
    // Преобразуване на списъка обратно в масив
    val array = Bytes.toArray(byteList)
    println(array.contentToString())  // [1, 2, 3]
}
```

**UnsignedInts, UnsignedLongs:**\
Поддръжка на цели числа без знак.

```kotlin
import com.google.common.primitives.UnsignedInts
import com.google.common.primitives.UnsignedLongs


fun unsignedIntsExample() {
    val unsignedInt = UnsignedInts.parseUnsignedInt("4294967295")  // Максимална стойност на unsigned int
    println(unsignedInt)  // 4294967295 (но се съхранява като обикновен int)
    val compared = UnsignedInts.compare(4000000000.toInt(), 3000000000.toInt())
    println(compared)  // 1 (първото е по-голямо от второто)
}


fun unsignedLongsExample() {
    val unsignedLong = UnsignedLongs.parseUnsignedLong("18446744073709551615")  // Максимална стойност на unsigned long
    println(unsignedLong)  // 18446744073709551615 (но се съхранява като обикновен long)
    val compared = UnsignedLongs.compare(18000000000000000000L, 17000000000000000000L)
    println(compared)  // 1 (първото е по-голямо от второто)
}
```

**Immutable collections for primitives:**\
Например ImmutableIntArray.

```kotlin
import com.google.common.primitives.ImmutableIntArray


fun immutableIntArrayExample() {
    // Създаване на неизменяем масив
    val immutableIntArray = ImmutableIntArray.of(1, 2, 3, 4, 5)
    println(immutableIntArray)  // [1, 2, 3, 4, 5]
    // Получаване на елемент
    println(immutableIntArray.get(2))  // 3
    // Опитът да се промени масивът предизвиква грешка
    // immutableIntArray.set(0, 10)  // UnsupportedOperationException
}
```

## Итератори и генератори

Google Guava предоставя мощни помощни инструменти за работа с итератори и генератори на данни. Те улесняват филтрирането, преобразуването и комбинирането на колекции, като предлагат гъвкав и удобен API. Ще разгледаме няколко примера за използване на итератори и генератори на данни на Kotlin.

**Iterators:**\
Помощни инструменти за работа с Java Iterator, например филтриране, преобразуване, обединяване и т. н.

Пример за филтриране на итератор:

```kotlin
import com.google.common.collect.Iterators


fun iteratorFilterExample() {
    val numbers = listOf(1, 2, 3, 4, 5).iterator()
    // Филтрираме итератора, като оставяме само четните числа
    val evenNumbers = Iterators.filter(numbers) { it % 2 == 0 }
    while (evenNumbers.hasNext()) {
        println(evenNumbers.next())  // 2, 4
    }
}
```

Пример за преобразуване на итератор:

```kotlin
import com.google.common.collect.Iterators
import com.google.common.base.Function


fun iteratorTransformExample() {
    val numbers = listOf(1, 2, 3, 4, 5).iterator()
    // Преобразуваме итератора, като повдигаме числата на квадрат
    val squaredNumbers = Iterators.transform(numbers, Function { it * it })
    while (squaredNumbers.hasNext()) {
        println(squaredNumbers.next())  // 1, 4, 9, 16, 25
    }
}
```

**PeekingIterator:**\
Итератор, който позволява да „надникнем“ към следващия елемент, без да го извличаме.

```kotlin
import com.google.common.collect.Iterators
import com.google.common.collect.PeekingIterator


fun peekingIteratorExample() {
    val numbers = listOf(1, 2, 3, 4, 5).iterator()
    val peekingIterator: PeekingIterator<Int> = Iterators.peekingIterator(numbers)
    while (peekingIterator.hasNext()) {
        println("Current: ${peekingIterator.next()}")
        if (peekingIterator.hasNext()) {
            println("Next (peek): ${peekingIterator.peek()}")
        }
    }
}
```

**AbstractIterator:**\
Шаблон за опростяване на създаването на потребителски итератори.

```kotlin
import com.google.common.collect.AbstractIterator


fun abstractIteratorExample() {
    val customIterator = object : AbstractIterator<Int>() {
        var count = 0
        override fun computeNext(): Int? {
            count++
            return if (count <= 5) count else endOfData() // Завършваме, когато count > 5
        }
    }
    while (customIterator.hasNext()) {
        println(customIterator.next())  // 1, 2, 3, 4, 5
    }
}
```

**UnmodifiableIterator:**\
Итератор, който не позволява промени. UnmodifiableIterator гарантира, че елементите не могат да бъдат променяни по време на итерацията.

```kotlin
import com.google.common.collect.UnmodifiableIterator

fun unmodifiableIteratorExample() {
    val numbers = listOf(1, 2, 3, 4, 5)

    // Създаваме неизменяем итератор
    val unmodifiableIterator: UnmodifiableIterator<Int> = object : UnmodifiableIterator<Int>() {
        private val iter = numbers.iterator()

        override fun hasNext(): Boolean = iter.hasNext()

        override fun next(): Int = iter.next()
    }

    while (unmodifiableIterator.hasNext()) {
        println(unmodifiableIterator.next())  // 1, 2, 3, 4, 5
    }

    // unmodifiableIterator.remove()  // UnsupportedOperationException
}
```

**FluentIterable:**\
Функционална работа с колекции. Макар че FluentIterable работи както с колекции, така и с итератори, той осигурява функционален стил на работа с тях, като обединява филтриране, преобразуване и други операции.

```kotlin
import com.google.common.collect.FluentIterable


fun fluentIterableExample() {
    val numbers = listOf(1, 2, 3, 4, 5)
    // Комбинираме филтриране и преобразуване с помощта на FluentIterable
    val result = FluentIterable.from(numbers)
        .filter { it % 2 == 0 } // Филтрираме четните числа
        .transform { it * 2 }   // Умножаваме всяко по 2
        .toList()
    println(result)  // [4, 8]
}
```

## Преобразуване на типове

Google Guava предоставя мощни помощни инструменти за преобразуване на типове, като TypeToken и Converter. Те позволяват да се работи с генерици, да се преобразуват обекти между различни типове и да се управлява сигурността на типовете по време на изпълнение.

**TypeToken:**\
Помощен инструмент за работа с типове, който поддържа генерици. TypeToken позволява да се работи с типове, особено с генерици, и да се извлича информация за тях по време на изпълнение. В стандартните Java и Kotlin системата от типове изтрива информацията за генериците по време на изпълнение, но с помощта на TypeToken може да се запази информацията за типа.

```kotlin
import com.google.common.reflect.TypeToken


fun typeTokenExample() {
    // Създаваме TypeToken за List<String>
    val typeToken = object : TypeToken<List<String>>() {}
    // Получаваме информация за типа
    val type = typeToken.type
    println(type)  // java.util.List<java.lang.String>
    // Проверяваме типа по време на изпълнение
    val listOfStrings: Any = listOf("a", "b", "c")
    if (typeToken.rawType.isAssignableFrom(listOfStrings.javaClass)) {
        println("listOfStrings е List<String>")
    }
}
```

**Converter:**\
Абстракция за преобразуване на един тип в друг с поддръжка на обратна конверсия. Converter позволява лесно да се преобразуват обекти от един тип в друг. Това е полезно, когато трябва да се определи преобразуване в двете посоки – напред и назад.

```kotlin
import com.google.common.base.Converter


fun converterExample() {
    // Определяме преобразувател между String и Integer
    val stringToIntegerConverter = object : Converter<String, Int>() {
        override fun doForward(string: String): Int {
            return string.toInt()
        }
        override fun doBackward(integer: Int): String {
            return integer.toString()
        }
    }
    // Преобразуваме низ в число
    val intValue = stringToIntegerConverter.convert("123")
    println(intValue)  // 123
    // Преобразуваме числото обратно в низ
    val stringValue = stringToIntegerConverter.reverse().convert(456)
    println(stringValue)  // "456"
}
```

**Enums:**\
Преобразуване на низове в изброими типове (и обратно). Guava улеснява и работата с изброимите типове (enums), като предлага помощни инструменти за преобразуването им от низове и обратно.

```kotlin
import com.google.common.base.Enums


enum class Color {
    RED, GREEN, BLUE
}


fun enumExample() {
    // Преобразуваме низ в стойност на изброим тип
    val color = Enums.getIfPresent(Color::class.java, "RED").orNull()
    println(color)  // RED
    // Получаваме низовото представяне на изброимия тип
    val colorName = Enums.stringConverter(Color::class.java).convert(Color.GREEN)
    println(colorName)  // GREEN
}
```

## Работа с времето

**Stopwatch:**\
Таймер за измерване на времето за изпълнение на операции.

```kotlin
import com.google.common.base.Stopwatch
import java.util.concurrent.TimeUnit


fun stopwatchExample() {
    // Създаваме таймер
    val stopwatch = Stopwatch.createStarted()
    // Изпълняваме някаква операция
    Thread.sleep(1000)
    // Спираме таймера
    stopwatch.stop()
    // Получаваме резултата в милисекунди
    println("Elapsed time: ${stopwatch.elapsed(TimeUnit.MILLISECONDS)} ms")  // Например: Elapsed time: 1001 ms
    // Таймерът може да се стартира отново
    stopwatch.reset().start()
    Thread.sleep(500)
    stopwatch.stop()
    println("Elapsed time after reset: ${stopwatch.elapsed(TimeUnit.MILLISECONDS)} ms")  // Например: Elapsed time after reset: 500 ms
}
```

**Timestamps:**\
Помощни инструменти за работа с отпечатъци на времето. Guava предлага и инструменти за работа с времеви отпечатъци и времеви интервали. Стандартен инструмент Timestamps в Guava обаче няма. Вместо него обикновено се използват класовете от пакета java.time (от Java 8). Въпреки това Stopwatch е основният инструмент на Guava за работа с времето.

**Пример за работа с класовете за време от Java 8 (за работа с времеви отпечатъци):**\
Макар че това не е част от Google Guava, от Java 8 можем да използваме java.time за работа с времеви отпечатъци и това често се прави заедно с инструментите на Guava.

```kotlin
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter


fun timestampExample() {
    // Получаваме текущия времеви отпечатък
    val currentTime = LocalDateTime.now()
    println("Current timestamp: $currentTime")  // Например: Current timestamp: 2023-10-01T15:45:32.123
    // Форматиране на времевия отпечатък
    val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
    val formattedTime = currentTime.format(formatter)
    println("Formatted timestamp: $formattedTime")  // Например: Formatted timestamp: 2023-10-01 15:45:32
}
```

## Работа с процеси

Google Guava предоставя абстракции за управление на услуги и процеси чрез пакетите com.google.common.util.concurrent и класа Service. Тези инструменти са особено полезни за управление на жизнения цикъл на процеси или услуги, които имат етапи на стартиране, изпълнение и спиране, което ги прави подходящи за дълготрайни процеси, като сървъри, фонова обработка на задачи и други продължителни операции.

**Service:**\
Абстракция за представяне на услуги с поддръжка на жизнен цикъл (инициализация, спиране и т. н.). Предоставя методи за управление на жизнения цикъл на процесите: стартиране, спиране, наблюдение на състоянието.

**AbstractExecutionThreadService:**\
AbstractExecutionThreadService предоставя шаблон за създаване на процеси, които трябва да се изпълняват в отделни нишки. Този клас позволява лесно да се стартира услуга във фонова нишка и да се обработва нейното завършване.

```kotlin
import com.google.common.util.concurrent.AbstractExecutionThreadService


fun abstractExecutionThreadServiceExample() {
    // Създаваме услуга, която работи в отделна нишка
    val backgroundService: Service = object : AbstractExecutionThreadService() {
        override fun run() {
            println("Background service is running")
            // Емулация на дълга операция
            Thread.sleep(5000)
            println("Background service has completed")
        }
        override fun startUp() {
            println("Background service is starting up")
        }
        override fun shutDown() {
            println("Background service is shutting down")
        }
    }
    // Стартираме услугата
    backgroundService.startAsync()
    backgroundService.awaitRunning()
    // Спираме услугата след работа
    backgroundService.stopAsync()
    backgroundService.awaitTerminated()
}
```

**ServiceManager:**\
Предоставя възможност да се управляват няколко услуги едновременно, да се следят техните състояния и да се завършва коректно работата им.

```kotlin
import com.google.common.util.concurrent.AbstractExecutionThreadService
import com.google.common.util.concurrent.Service
import com.google.common.util.concurrent.ServiceManager


fun serviceManagerExample() {
    // Създаваме две услуги
    val service1: Service = object : AbstractExecutionThreadService() {
        override fun run() {
            println("Service 1 is running...")
            Thread.sleep(2000)
        }
        override fun shutDown() {
            println("Service 1 is shutting down...")
        }
    }
    val service2: Service = object : AbstractExecutionThreadService() {
        override fun run() {
            println("Service 2 is running...")
            Thread.sleep(3000)
        }
        override fun shutDown() {
            println("Service 2 is shutting down...")
        }
    }
    // Използваме ServiceManager за управление на двете услуги
    val serviceManager = ServiceManager(listOf(service1, service2))
    // Добавяме обработчик за известяване при завършване на всички услуги
    serviceManager.addListener(object : ServiceManager.Listener() {
        override fun stopped() {
            println("All services have stopped.")
        }
        override fun failure(service: Service) {
            println("Service failed: ${service.javaClass.name}")
        }
    }, Runnable::run)
    // Стартираме всички услуги
    serviceManager.startAsync()
    serviceManager.awaitHealthy()  // Изчакване на стартирането на всички услуги
    // Спираме всички услуги
    serviceManager.stopAsync()
    serviceManager.awaitStopped()  // Изчакване на спирането на всички услуги
}
```

## Конкурентно програмиране

**ListenableFuture:**\
Разширение на стандартния Future, което поддържа добавяне на колбеци.

```kotlin
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.MoreExecutors
import com.google.common.util.concurrent.ListenableFutureTask
import java.util.concurrent.Executors


fun listenableFutureExample() {
    // Създаваме executor за изпълнение на задачи
    val executor = Executors.newSingleThreadExecutor()
    // Създаваме ListenableFutureTask за асинхронна операция
    val futureTask: ListenableFuture<String> = ListenableFutureTask.create<String> {
        Thread.sleep(2000)  // Емулация на дълга задача
        "Task result"
    }
    // Добавяме колбек за обработка на резултата
    futureTask.addListener({
        try {
            println("Task completed with result: ${futureTask.get()}")
        } catch (e: Exception) {
            println("Error during task execution: ${e.message}")
        }
    }, MoreExecutors.directExecutor())
    // Стартираме задачата
    executor.submit(futureTask)
}
```

**Futures:**\
Помощни инструменти за работа с ListenableFuture, включително композиция и комбиниране на няколко бъдещи стойности.

```kotlin
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFutureTask
import java.util.concurrent.Executors


fun futuresExample() {
    // Създаваме executor за изпълнение на задачи
    val executor = Executors.newFixedThreadPool(2)
    // Създаваме две асинхронни задачи
    val futureTask1 = ListenableFutureTask.create<String> {
        Thread.sleep(1000)
        "Result from Task 1"
    }
    val futureTask2 = ListenableFutureTask.create<String> {
        Thread.sleep(2000)
        "Result from Task 2"
    }
    // Стартираме задачите
    executor.submit(futureTask1)
    executor.submit(futureTask2)
    // Комбинираме резултатите от двете задачи
    val combinedFuture = Futures.allAsList(futureTask1, futureTask2)
    // Добавяме колбек за обработка на резултата
    combinedFuture.addListener({
        try {
            val results = combinedFuture.get()
            println("All tasks completed with results: $results")
        } catch (e: Exception) {
            println("Error: ${e.message}")
        }
    }, MoreExecutors.directExecutor())
}
```

**MoreExecutors:**\
Разширени помощни инструменти за работа с екзекютори (например преобразуване на екзекютор в ListenableFuture).

```kotlin
import com.google.common.util.concurrent.MoreExecutors
import java.util.concurrent.Executors


fun moreExecutorsExample() {
    // Създаваме executor с автоматично завършване на работата, когато всички задачи приключат
    val executor = MoreExecutors.getExitingExecutorService(Executors.newSingleThreadExecutor())
    // Стартираме задача
    executor.submit {
        println("Task is running in exiting executor")
    }
    // Екзекюторът автоматично ще завърши работата си, когато всички задачи приключат
}
```

**ListeningExecutorService:**\
Разширява ExecutorService и поддържа създаване на задачи, които връщат ListenableFuture. Това е удобно за управление на асинхронни задачи с колбеци.

```kotlin
import com.google.common.util.concurrent.ListeningExecutorService
import com.google.common.util.concurrent.MoreExecutors
import java.util.concurrent.Executors


fun listeningExecutorServiceExample() {
    // Създаваме ListeningExecutorService
    val executorService: ListeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2))
    // Стартираме асинхронна задача
    val future = executorService.submit<String> {
        Thread.sleep(1000)
        "Async result"
    }
    // Добавяме колбек за обработка на резултата
    future.addListener({
        try {
            println("Task completed with result: ${future.get()}")
        } catch (e: Exception) {
            println("Error: ${e.message}")
        }
    }, MoreExecutors.directExecutor())
}
```

**RateLimiter:**\
Използва се за ограничаване на скоростта на изпълнение на операции, например за контрол на броя заявки в секунда.

```kotlin
import com.google.common.util.concurrent.RateLimiter


fun rateLimiterExample() {
    // Създаваме RateLimiter с лимит от 2 операции в секунда
    val rateLimiter = RateLimiter.create(2.0)
    // Изпълняваме операции с ограничение на скоростта
    for (i in 1..5) {
        rateLimiter.acquire()  // Блокираме изпълнението, докато лимитът не позволи да се продължи
        println("Executing task $i at ${System.currentTimeMillis()}")
    }
}
```

## Помощни инструменти за работа с IO

**Files:**\
Помощни инструменти за работа с файлове (копиране, преместване, четене, запис и т. н.).

Пример за четене и запис на файлове:

```kotlin
import com.google.common.io.Files
import java.io.File
import java.nio.charset.StandardCharsets


fun filesExample() {
    val file = File("example.txt")
    // Записваме данни във файла
    Files.asCharSink(file, StandardCharsets.UTF_8).write("Hello, world!")
    // Четем данни от файла
    val content = Files.asCharSource(file, StandardCharsets.UTF_8).read()
    println("File content: $content")  // Hello, world!
}
```

Пример за копиране на файл:

```kotlin
import com.google.common.io.Files
import java.io.File


fun fileCopyExample() {
    val sourceFile = File("source.txt")
    val targetFile = File("target.txt")
    // Копираме файла
    Files.copy(sourceFile, targetFile)
    println("File copied from ${sourceFile.name} to ${targetFile.name}")
}
```

Пример за преместване на файл:

```kotlin
import com.google.common.io.Files
import java.io.File


fun fileMoveExample() {
    val sourceFile = File("source.txt")
    val targetFile = File("moved.txt")
    // Преместваме файла
    Files.move(sourceFile, targetFile)
    println("File moved from ${sourceFile.name} to ${targetFile.name}")
}
```

**CharStreams:**\
Помощни инструменти за работа с потоци от символи.

Пример за четене на данни от Reader:

```kotlin
import com.google.common.io.CharStreams
import java.io.StringReader


fun charStreamsExample() {
    val reader = StringReader("Hello from StringReader!")
    // Четем всички данни от Reader
    val content = CharStreams.toString(reader)
    println(content)  // Hello from StringReader!
}
```

Пример за запис на данни във Writer:

```kotlin
import com.google.common.io.CharStreams
import java.io.StringWriter


fun charStreamsWriteExample() {
    val writer = StringWriter()
    // Записваме данни във Writer
    CharStreams.asWriter(writer).write("Hello to StringWriter!")
    println(writer.toString())  // Hello to StringWriter!
}
```

**ByteStreams:**\
Помощни инструменти за работа с байтови потоци.

Пример за копиране на данни от един поток в друг:

```kotlin
import com.google.common.io.ByteStreams
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream


fun byteStreamsExample() {
    val input = ByteArrayInputStream("Hello in bytes!".toByteArray())
    val output = ByteArrayOutputStream()
    // Копираме данните от InputStream в OutputStream
    ByteStreams.copy(input, output)
    println(output.toString())  // Hello in bytes!
}
```

Пример за четене на всички данни от InputStream:

```kotlin
import com.google.common.io.ByteStreams
import java.io.ByteArrayInputStream


fun byteStreamsReadExample() {
    val input = ByteArrayInputStream("Some byte data".toByteArray())
    // Четем всички данни от InputStream
    val byteData = ByteStreams.toByteArray(input)
    println(String(byteData))  // Some byte data
}
```

**Closer:**\
Опростява управлението на ресурси, като файлове и потоци, като осигурява автоматичното им затваряне както при грешка, така и при успешно завършване на работата.

```kotlin
import com.google.common.io.Closer
import java.io.FileReader
import java.io.FileWriter


fun closerExample() {
    val closer = Closer.create()
    try {
        // Отваряме ресурсите
        val reader = closer.register(FileReader("input.txt"))
        val writer = closer.register(FileWriter("output.txt"))
        // Четем данните и ги записваме
        val data = reader.readText()
        writer.write(data)
    } catch (e: Exception) {
        println("Error occurred: ${e.message}")
        throw e
    } finally {
        closer.close()  // Автоматично затваря всички ресурси
    }
}
```

**Resources:**\
Guava предоставя и помощни инструменти за работа с ресурси под формата на файлове, които се намират в classpath.

```kotlin
import com.google.common.io.Resources
import java.nio.charset.StandardCharsets


fun resourcesExample() {
    // Четем ресурс от classpath
    val url = Resources.getResource("config.txt")
    val content = Resources.toString(url, StandardCharsets.UTF_8)
    println(content)
}
```

## Помощни инструменти за работа с потоци (Streams)

**Stream:**\
Разширени помощни инструменти за работа с потоци от данни.

```kotlin
import com.google.common.collect.Streams


fun streamsExample() {
    val list1 = listOf(1, 2, 3)
    val list2 = listOf(4, 5, 6)
    // Обединяваме два списъка в един поток
    val combinedStream = Streams.concat(list1.stream(), list2.stream())
    // Преобразуваме потока в списък
    val combinedList = combinedStream.toList()
    println(combinedList)  // [1, 2, 3, 4, 5, 6]
}
```

Инструментът Streams.zip позволява да се обединят два потока в един с помощта на функция:

```kotlin
import com.google.common.collect.Streams
import java.util.stream.Stream


fun streamsZipExample() {
    val stream1 = Stream.of(1, 2, 3)
    val stream2 = Stream.of("a", "b", "c")
    // Обединяваме двата потока, като създаваме двойки (число, низ)
    val zippedStream = Streams.zip(stream1, stream2) { number, letter -> "$number$letter" }
    // Преобразуваме потока в списък
    val result = zippedStream.toList()
    println(result)  // [1a, 2b, 3c]
}
```

## Hashing (Хеширане)

**Hashing:**\
Поддръжка на различни хеш функции (MD5, SHA-256, MurmurHash и др.).

```kotlin
import com.google.common.hash.Hashing
import java.nio.charset.StandardCharsets


fun hashingExample() {
    val input = "Hello, World!"
    // Използваме SHA-256 за хеширане на низа
    val hash = Hashing.sha256()
        .hashString(input, StandardCharsets.UTF_8)
        .toString()
    println("SHA-256 hash: $hash")
    // Пример за изход: SHA-256 hash: c0535e4be2b79ffd93291305436bf889314e4a3d9a91fb217b0b14cba2999e66
}
```

```kotlin
import com.google.common.hash.Hashing
import java.nio.charset.StandardCharsets


fun murmurHashExample() {
    val input = "Guava Hashing Example"
    // Използваме MurmurHash3 за хеширане на низа
    val hash = Hashing.murmur3_128()
        .hashString(input, StandardCharsets.UTF_8)
        .toString()
    println("MurmurHash3 (128-bit) hash: $hash")
    // Пример за изход: MurmurHash3 (128-bit) hash: 2f17b911e9d9b22fa10f0ab091d02e17
}
```

**Hasher:**\
Позволява данните за хеширане да се добавят поетапно. Това е полезно, ако трябва да се хешират данни, постъпващи от няколко източника, или данни, които трябва да се хешират последователно.

```kotlin
import com.google.common.hash.Hashing
import java.nio.charset.StandardCharsets

fun hasherExample() {
    val hasher = Hashing.sha256().newHasher()

    // Добавяме данните за хеширане на части
    hasher.putString("Hello", StandardCharsets.UTF_8)
    hasher.putInt(12345)
    hasher.putLong(9876543210L)

    // Получаваме крайния хеш
    val hash = hasher.hash().toString()

    println("Combined SHA-256 hash: $hash")
    // Пример за изход: Combined SHA-256 hash: 3627904d36e33402e1dba8e132ea9d222f3baaf3dcb9bfb144f50c3cf555160b
}
```

**HashCode:**\
Представлява резултата от хеширането, който може да се преобразува в низ, масив от байтове или да се използва за сравнение.

```kotlin
import com.google.common.hash.Hashing
import java.nio.charset.StandardCharsets


fun hashCodeExample() {
    val hashCode = Hashing.sha256()
        .hashString("Guava HashCode Example", StandardCharsets.UTF_8)
    // Преобразуваме хеша в низ
    println("Hash as string: ${hashCode.toString()}")
    // Преобразуваме хеша в масив от байтове
    val byteArray = hashCode.asBytes()
    println("Hash as byte array: ${byteArray.contentToString()}")
}
```

**BloomFilter:**\
вероятностна структура от данни, която се използва за проверка дали елемент принадлежи към множество, с малка вероятност за фалшиви положителни резултати. Този инструмент е полезен, когато се изисква да се спестява памет и може да се допусне малка вероятност за фалшиви положителни резултати.

```kotlin
import com.google.common.hash.BloomFilter
import com.google.common.hash.Funnels


fun bloomFilterExample() {
    // Създаваме филтър на Блум за низове с очакван брой вмъквания 1000 и вероятност за фалшиви положителни резултати 0.01
    val bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1000, 0.01)
    // Добавяме данни във филтъра
    bloomFilter.put("Guava")
    bloomFilter.put("BloomFilter")
    bloomFilter.put("Hashing")
    // Проверяваме наличието на елементи
    println("Might contain 'Guava': ${bloomFilter.mightContain("Guava")}")  // true
    println("Might contain 'Hashing': ${bloomFilter.mightContain("Hashing")}")  // true
    println("Might contain 'Unknown': ${bloomFilter.mightContain("Unknown")}")  // false (вероятност за фалшив положителен резултат 0.01)
}
```

**Custom Hash Functions:**\
Създаване на собствена хеш функция. Ако вградените алгоритми за хеширане не са подходящи, може да се създаде собствена хеш функция чрез имплементиране на интерфейса HashFunction.

```kotlin
import com.google.common.hash.AbstractHasher
import com.google.common.hash.HashFunction
import com.google.common.hash.HashCode


fun customHashFunctionExample() {
    val customHashFunction = object : HashFunction {
        override fun newHasher() = object : AbstractHasher() {
            private var sum = 0
            override fun putInt(i: Int): AbstractHasher {
                sum += i
                return this
            }
            override fun putString(input: CharSequence, charset: java.nio.charset.Charset): AbstractHasher {
                sum += input.length
                return this
            }
            override fun hash(): HashCode {
                return HashCode.fromInt(sum)
            }
        }
        override fun bits(): Int = 32
    }
    val hasher = customHashFunction.newHasher()
    hasher.putInt(123)
    hasher.putString("custom hash function", StandardCharsets.UTF_8)
    val hash = hasher.hash()
    println("Custom hash code: ${hash.asInt()}")
    // Пример за изход: Custom hash code: 143
}
```

## Математически инструменти

**Ints, Longs, Doubles, BigIntegerMath, DoubleMath:**\
Помощни инструменти за математически операции с числа от различни типове.

**RoundingMode:**\
Помощни инструменти за закръгляване на числа.

## Работа с анотации

**@Beta:**\
Маркировка за нестабилни API. Показва, че API може да се промени в бъдеще. Анотацията @Beta се използва за маркиране на класове, методи и API, които могат да се променят в бъдещи версии. Този API не се счита за стабилен и използването му в продукция се препоръчва да става внимателно, тъй като може да се промени без обратна съвместимост.

```kotlin
import com.google.common.annotations.Beta


@Beta
class BetaFeature {
    fun newFeature() {
        println("This feature is in beta and may change!")
    }
}


fun betaFeatureExample() {
    val feature = BetaFeature()
    feature.newFeature()
}
```

**@VisibleForTesting:**\
Достъпност за тестване. Показва, че методът или класът е предназначен за използване в тестове. Анотацията @VisibleForTesting се използва, за да се покаже, че определен метод или поле са достъпни само за тестове. Това може да е полезно за означаване на методи, които не са предназначени за използване извън тестовете, но са отворени за тестване.

```kotlin
import com.google.common.annotations.VisibleForTesting


class ProductionClass {
    // Този метод е достъпен само за тестове
    @VisibleForTesting
    internal fun internalLogicForTests(): Int {
        return 42
    }
    fun publicLogic(): String {
        return "Public logic result"
    }
}


fun testVisibilityExample() {
    val productionClass = ProductionClass()
    // Методът може да се извиква в тестове
    val testResult = productionClass.internalLogicForTests()
    println("Test logic result: $testResult")  // Test logic result: 42
}
```

**@Nullable:**\
Анотация за указване на възможност за null. Анотацията @Nullable показва, че методът може да връща null или че параметърът на метода може да приема стойност null. Това помага да се повишат сигурността и прозрачността на кода, като се показва къде може да възникне null.

```kotlin
import javax.annotation.Nullable


class NullableExample {
    // Методът може да върне null
    @Nullable
    fun findValue(key: String): String? {
        return if (key == "exists") "Found value" else null
    }
}


fun nullableExample() {
    val example = NullableExample()
    val value = example.findValue("not_exists")
    println("Value: $value")  // Value: null
}
```

**@CheckReturnValue:**\
Задължителна проверка на върнатата стойност. Анотацията @CheckReturnValue показва, че върнатата стойност на метода трябва да се провери и че пренебрегването ѝ може да доведе до грешка. Тази анотация е полезна за методи, чийто резултат е важно да се обработи.

```kotlin
import com.google.errorprone.annotations.CheckReturnValue


class CheckReturnValueExample {

    @CheckReturnValue
    fun computeValue(): Int {
        return 42
    }
}


fun checkReturnValueExample() {
    val example = CheckReturnValueExample()
    // Предполага се, че тази стойност трябва да бъде използвана
    val result = example.computeValue()
    println("Computed value: $result")  // Computed value: 42
}
```

**@CanIgnoreReturnValue:**\
Разрешение за пренебрегване на върнатата стойност. Анотацията @CanIgnoreReturnValue позволява върнатата стойност на метода да се пренебрегне. Тя е полезна в ситуации, когато върнатата стойност не е задължително да се използва.

```kotlin
import com.google.errorprone.annotations.CanIgnoreReturnValue


class IgnoreReturnValueExample {

    @CanIgnoreReturnValue
    fun performAction(): String {
        return "Action performed"
    }
}


fun ignoreReturnValueExample() {
    val example = IgnoreReturnValueExample()
    // Върнатата стойност може да се пренебрегне
    example.performAction()  // Стойността не е задължително да се използва
}
```

## Други помощни инструменти

**Preconditions:**\
Помощни инструменти за проверка на условия, които се използват за валидиране на аргументите на методите. Google Guava предоставя инструмента Preconditions, който помага да се извършват проверки на аргументите на методите и на състоянията на програмата. Тези проверки повишават четимостта и надеждността на кода, защото позволяват да се хвърлят изключения с информативни съобщения при некоректни данни.

Инструментът Preconditions предоставя следните основни методи:

**checkArgument:** \
използва се за проверка на условия, свързани с подадените аргументи. Ако условието не е изпълнено, се хвърля IllegalArgumentException.

```kotlin
import com.google.common.base.Preconditions


fun checkArgumentExample(age: Int) {
    // Проверка дали възрастта е по-голяма или равна на 18
    Preconditions.checkArgument(age >= 18, "Age must be 18 or older, but was %s", age)
    println("Valid age: $age")
}


fun main() {
    checkArgumentExample(20)  // Valid age: 20
    // checkArgumentExample(15)  // IllegalArgumentException: Age must be 18 or older, but was 15
}
```

**checkNotNull:** \
проверява дали подаденият аргумент не е равен на null. Ако аргументът е null, се хвърля NullPointerException.

```kotlin
import com.google.common.base.Preconditions


fun checkNotNullExample(name: String?) {
    // Проверка дали името не е равно на null
    val validName = Preconditions.checkNotNull(name, "Name cannot be null")
    println("Valid name: $validName")
}


fun main() {
    checkNotNullExample("Alice")  // Valid name: Alice
    // checkNotNullExample(null)  // NullPointerException: Name cannot be null
}
```

**checkState:** \
използва се за проверка на състоянието на обект. Ако условието не е изпълнено, се хвърля IllegalStateException.

```kotlin
import com.google.common.base.Preconditions


class StateExample(private var isInitialized: Boolean) {
    fun doSomething() {
        // Проверка дали обектът е инициализиран
        Preconditions.checkState(isInitialized, "Object must be initialized before use")

        println("Doing something")
    }
    fun initialize() {
        isInitialized = true
    }
}


fun main() {
    val example = StateExample(false)
    // example.doSomething()  // IllegalStateException: Object must be initialized before use
    example.initialize()
    example.doSomething()  // Doing something
}
```

**checkElementIndex:** \
проверява дали индексът на елемента е в рамките на допустимия диапазон (от 0 до размера на списъка/масива). Ако индексът излиза извън границите, се хвърля IndexOutOfBoundsException.

```kotlin
import com.google.common.base.Preconditions


fun checkElementIndexExample(index: Int, list: List<String>) {
    // Проверка дали индексът е в рамките на списъка
    Preconditions.checkElementIndex(index, list.size, "Invalid index")
    println("Element at index $index: ${list[index]}")
}


fun main() {
    val list = listOf("apple", "banana", "cherry")
    checkElementIndexExample(1, list)  // Element at index 1: banana
    // checkElementIndexExample(5, list)  // IndexOutOfBoundsException: Invalid index (5) must be less than size (3)
}
```

**checkPositionIndex:** \
проверява позиция в колекция или масив. Позицията е индекс, който може да сочи към началото или към края на колекцията. Ако позицията е невалидна, се хвърля IndexOutOfBoundsException.

```kotlin
import com.google.common.base.Preconditions


fun checkPositionIndexExample(position: Int, list: List<String>) {
    // Проверка на позицията
    Preconditions.checkPositionIndex(position, list.size, "Invalid position")
    println("Valid position: $position")
}


fun main() {
    val list = listOf("apple", "banana", "cherry")
    checkPositionIndexExample(3, list)  // Valid position: 3 (сочи към края на списъка)
    // checkPositionIndexExample(5, list)  // IndexOutOfBoundsException: Invalid position (5) must be less than size (3)
}
```

**checkPositionIndexes:** \
проверява дали началният и крайният индекс са в допустимия диапазон и дали началният индекс не е по-голям от крайния.

```kotlin
import com.google.common.base.Preconditions


fun checkPositionIndexesExample(start: Int, end: Int, list: List<String>) {
    // Проверка на диапазона от индекси
    Preconditions.checkPositionIndexes(start, end, list.size)
    println("Valid range: from $start to $end")
}


fun main() {
    val list = listOf("apple", "banana", "cherry", "date")
    checkPositionIndexesExample(0, 2, list)  // Valid range: from 0 to 2
    // checkPositionIndexesExample(2, 5, list)  // IndexOutOfBoundsException: End index (5) must not be greater than size (4)
}
```

**Objects:**\
Помощни инструменти за работа с обекти (сравнение, генериране на hashCode и т. н.).

**MoreObjects:**\
Допълнителни помощни инструменти за работа с обекти, включително toStringHelper.

**ComparisonChain:**\
Помощен инструмент за създаване на вериги от сравнения на обекти, който опростява имплементацията на методите compareTo.

[ Copyright: Roman Kryvolapov ](https://t.me/RomanKryvolapov)
