# Guava User Guide

Guava is a set of core Java libraries from Google. It supplies the building blocks that the
standard library leaves out: immutable collections, new collection types such as multimaps and
multisets, a graph library, an in-memory cache, and polished utilities for concurrency, I/O,
hashing, math, primitives, strings, and networking. This guide shows you how to **use** Guava
from your own Java code — every section is grounded in the library's actual public API.

> [!NOTE]
> Guava is a **library**, not an application. There is no command to run and nothing to deploy.
> You add it to your build and call its classes. Throughout this guide, "you" means a Java
> developer writing code against Guava's API.

---

## 1. Quick Start

Add the dependency, then start calling Guava.

**Maven** (`pom.xml`):

```xml
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>33.6.0-jre</version>
</dependency>
```

A first taste — immutable collections, null-safe optionals, and string joining:

```java
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;

ImmutableList<String> colors = ImmutableList.of("red", "green", "blue");

String csv = Joiner.on(", ").join(colors);
System.out.println(csv);
```

```text
red, green, blue
```

```java
Optional<String> maybe = Optional.of("present");
System.out.println(maybe.isPresent());   // true
System.out.println(maybe.or("default")); // present
```

```text
true
present
```

> [!TIP]
> The fastest way to find a class is **guava.dev**. Append any class name to jump straight to its
> Javadoc — for example, [`guava.dev/ImmutableList`](https://guava.dev/ImmutableList). The full
> API index lives at [`guava.dev/api`](https://guava.dev/api).

---

## 2. Installation

### 2.1 Coordinates and flavors

Guava's Maven group ID is `com.google.guava` and its artifact ID is `guava`. It ships in **two
flavors**, selected by a suffix on the version string:

| Flavor | Version suffix | Requires | Use when |
|--------|----------------|----------|----------|
| **JRE** | `-jre` (e.g. `33.6.0-jre`) | JDK 1.8 or higher | Server, desktop, or any standard JVM |
| **Android** | `-android` (e.g. `33.6.0-android`) | Android, or any library that must stay Android-compatible | Android apps, or libraries consumed by Android projects |

> [!IMPORTANT]
> The flavor is chosen **only** through the version suffix — the group ID and artifact ID are
> identical for both. Mixing the two on one classpath is unsupported; pick one and be consistent
> across your whole dependency graph.

### 2.2 Adding Guava to your build

=== "Maven"

    ```xml
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>33.6.0-jre</version>
      <!-- or, for Android: -->
      <!-- <version>33.6.0-android</version> -->
    </dependency>
    ```

=== "Gradle (JRE)"

    ```gradle
    dependencies {
      // Use Guava in your implementation only:
      implementation("com.google.guava:guava:33.6.0-jre")

      // Or, if Guava types appear in your own public API:
      api("com.google.guava:guava:33.6.0-jre")
    }
    ```

=== "Gradle (Android)"

    ```gradle
    dependencies {
      // Implementation only:
      implementation("com.google.guava:guava:33.6.0-android")

      // Or, if Guava types appear in your public API:
      api("com.google.guava:guava:33.6.0-android")
    }
    ```

> [!TIP]
> Use `implementation` when Guava types stay inside your module, and `api` only when a Guava type
> appears in a method signature you expose to downstream modules. This keeps Guava off your
> consumers' compile classpath when they don't need it.

### 2.3 Always use the latest release

The version `33.6.0-jre` shown above is the current release at the time of writing. Check the
[releases page](https://github.com/google/guava/releases/latest) for the newest version and update
the suffix accordingly.

> [!WARNING]
> A version of the form `999.0.0-HEAD-jre-SNAPSHOT` (or `-android-SNAPSHOT`) is a **development
> snapshot built from the `master` branch**, not a stable release. Use a numbered release like
> `33.6.0-jre` in production builds unless you specifically need an unreleased fix.

### 2.4 What gets pulled in

Guava has exactly **one** dependency required for linkage at runtime:
`com.google.guava:failureaccess:1.0.3`. Your build tool resolves it automatically. The remaining
declared dependencies are annotation-only (used at compile time) and do not add runtime weight.

```text
com.google.guava:guava:33.6.0-jre
└── com.google.guava:failureaccess:1.0.3   (the only runtime dependency)
```

---

## 3. Null Handling and Argument Checking

### 3.1 `Optional` — explicit absence

`com.google.common.base.Optional<T>` represents a value that may or may not be present, forcing
callers to deal with absence instead of risking a `NullPointerException`.

```java
import com.google.common.base.Optional;

Optional<Integer> present = Optional.of(5);   // throws if you pass null
Optional<Integer> absent  = Optional.absent();
Optional<Integer> nul     = Optional.fromNullable(getMaybeNull());

int a = present.get();          // 5  — throws IllegalStateException if absent
int b = absent.or(0);           // 0  — supply a default
boolean ok = present.isPresent(); // true
```

Useful operations on `Optional`:

| Method | Purpose |
|--------|---------|
| `Optional.of(T)` | Wrap a non-null value (throws on null) |
| `Optional.absent()` | An empty optional |
| `Optional.fromNullable(T)` | Wrap a possibly-null value |
| `get()` | The value, or `IllegalStateException` if absent |
| `or(T default)` | The value, or a fallback |
| `or(Supplier<T>)` | The value, or a lazily-computed fallback |
| `transform(Function)` | Map the value if present |
| `asSet()` | A 0- or 1-element immutable set |
| `toJavaUtil()` | Convert to `java.util.Optional` |

> [!NOTE]
> If you target Java 8+, `java.util.Optional` covers most of the same ground. Guava's `Optional`
> predates it and remains useful for interop and for the `transform`/`or(Supplier)` style.
> `toJavaUtil()` and `Optional.fromJavaUtil(...)` bridge the two.

### 3.2 `Preconditions` — fail fast on bad input

`com.google.common.base.Preconditions` turns validation into one-liners that throw the right
exception type with a clear message.

```java
import static com.google.common.base.Preconditions.*;

void setAge(int age) {
  checkArgument(age >= 0, "age must be non-negative, was %s", age); // IllegalArgumentException
  this.age = age;
}

void start() {
  checkState(!running, "already running");                          // IllegalStateException
  this.config = checkNotNull(config, "config");                     // NullPointerException
}

String get(int index) {
  checkElementIndex(index, size);   // IndexOutOfBoundsException with a helpful message
  return data[index];
}
```

| Method | Throws | Checks |
|--------|--------|--------|
| `checkArgument(boolean, ...)` | `IllegalArgumentException` | A method argument |
| `checkState(boolean, ...)` | `IllegalStateException` | Object state |
| `checkNotNull(T, ...)` | `NullPointerException` | A reference is non-null (returns it) |
| `checkElementIndex(index, size)` | `IndexOutOfBoundsException` | A valid element index `[0, size)` |
| `checkPositionIndex(index, size)` | `IndexOutOfBoundsException` | A valid position `[0, size]` |

> [!TIP]
> The message templates use `%s` placeholders and are formatted lazily — the substitution only
> happens when the check actually fails, so there is no cost on the success path.

### 3.3 `Verify` — check invariants you expect to hold

`com.google.common.base.Verify` is `Preconditions`' sibling for verifying conditions that *should*
already be true (it throws `VerifyException` rather than `IllegalArgumentException`/`IllegalStateException`).

```java
import static com.google.common.base.Verify.*;

Bar bar = doSomething();
verify(bar.isOk(), "doSomething() returned a not-ok Bar: %s", bar);
String name = verifyNotNull(bar.name());
```

---

## 4. String Utilities

### 4.1 `Splitter` — predictable splitting

Unlike `String.split`, `Splitter` never silently drops trailing empty strings or applies surprising
regex semantics. You configure it explicitly.

```java
import com.google.common.base.Splitter;

// "a,b,,c" -> ["a", "b", "", "c"]   (empties kept by default)
List<String> raw = Splitter.on(',').splitToList("a,b,,c");

// Trim and drop empties:
List<String> clean = Splitter.on(',')
    .trimResults()
    .omitEmptyStrings()
    .splitToList(" a, b, ,c ");        // ["a", "b", "c"]

// Parse "key=val;key2=val2" into a Map:
Map<String, String> m = Splitter.on(';')
    .withKeyValueSeparator('=')
    .split("a=1;b=2");                 // {a=1, b=2}
```

| Factory / modifier | Effect |
|--------------------|--------|
| `on(char)` / `on(String)` / `on(Pattern)` | Split on a separator |
| `onPattern(String)` | Split on a regex given as a string |
| `fixedLength(int)` | Split into fixed-size chunks |
| `trimResults()` / `trimResults(CharMatcher)` | Trim each piece |
| `omitEmptyStrings()` | Drop empty pieces |
| `limit(int)` | Stop after N pieces |
| `splitToList(...)` / `splitToStream(...)` | Materialize results |
| `withKeyValueSeparator(...)` | Produce a `Map` |

### 4.2 `Joiner` — the inverse of `Splitter`

```java
import com.google.common.base.Joiner;

Joiner.on("; ").join(1, 2, 3);                         // "1; 2; 3"
Joiner.on(", ").skipNulls().join("a", null, "b");      // "a, b"
Joiner.on(", ").useForNull("N/A").join("a", null);     // "a, N/A"

Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);
Joiner.on(", ").withKeyValueSeparator("=").join(map);  // "a=1, b=2"
```

> [!CAUTION]
> A `Joiner` is immutable; methods like `skipNulls()` and `useForNull(...)` return a **new**
> configured instance rather than mutating the original. Always use the returned value.

### 4.3 `Strings`, `Ascii`, and `CaseFormat`

```java
import com.google.common.base.Strings;
import com.google.common.base.Ascii;
import com.google.common.base.CaseFormat;

Strings.padStart("7", 3, '0');           // "007"
Strings.padEnd("7", 3, '0');             // "700"
Strings.repeat("ab", 3);                 // "ababab"
Strings.commonPrefix("foobar", "foobaz");// "fooba"
Strings.nullToEmpty(null);               // ""
Strings.isNullOrEmpty("");               // true

Ascii.toUpperCase("hello");              // "HELLO" (ASCII-only, locale-independent)
Ascii.truncate("Hello, World", 8, "..."); // "Hello..."

// Convert identifier casing:
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "my_field"); // "MyField"
CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, "MyField");      // "my-field"
```

`CaseFormat` constants: `LOWER_HYPHEN`, `LOWER_UNDERSCORE`, `LOWER_CAMEL`, `UPPER_CAMEL`,
`UPPER_UNDERSCORE`.

### 4.4 `CharMatcher` — match, count, trim, and replace characters

`CharMatcher` describes a class of characters and applies it across a `CharSequence`.

```java
import com.google.common.base.CharMatcher;

CharMatcher digits = CharMatcher.inRange('0', '9');
digits.retainFrom("a1b2c3");                // "123"
digits.removeFrom("a1b2c3");                // "abc"
digits.countIn("a1b2c3");                   // 3

CharMatcher.whitespace().trimAndCollapseFrom("  a   b ", ' '); // "a b"
CharMatcher.anyOf("aeiou").replaceFrom("banana", '*');         // "b*n*n*"
```

| Common factory | Matches |
|----------------|---------|
| `any()` / `none()` | Everything / nothing |
| `whitespace()` / `breakingWhitespace()` | Whitespace characters |
| `ascii()` | ASCII characters |
| `digit()` / `javaLetterOrDigit()` | Digits / letters & digits |
| `is(char)` / `isNot(char)` | A single character |
| `anyOf(CharSequence)` / `noneOf(...)` | Any/none of the given chars |
| `inRange(char, char)` | A contiguous range |

Matchers compose with `negate()`, `and(...)`, and `or(...)`.

---

## 5. Object Helpers: `equals`, `hashCode`, `toString`, and Comparison

### 5.1 `MoreObjects` and `Objects`

```java
import com.google.common.base.MoreObjects;
import java.util.Objects;   // JDK

// Readable toString():
@Override public String toString() {
  return MoreObjects.toStringHelper(this)
      .add("id", id)
      .add("name", name)
      .omitNullValues()
      .toString();                // ClassName{id=42, name=Ada}
}

// First non-null:
String label = MoreObjects.firstNonNull(custom, "default");
```

> [!NOTE]
> For `equals` and `hashCode`, Guava recommends the JDK's own `java.util.Objects.equals(a, b)` and
> `java.util.Objects.hash(...)` — there is no need for a Guava equivalent on Java 7+.

### 5.2 `ComparisonChain` — multi-field comparisons

```java
import com.google.common.collect.ComparisonChain;

@Override public int compareTo(Person that) {
  return ComparisonChain.start()
      .compare(this.lastName, that.lastName)
      .compare(this.firstName, that.firstName)
      .compare(this.age, that.age)          // primitive int — no boxing
      .result();
}
```

The chain stops evaluating as soon as a non-zero result is found.

### 5.3 `Ordering` — power-tool comparators

`Ordering<T>` is a `Comparator` with extra combinators and helper methods.

```java
import com.google.common.collect.Ordering;

Ordering<String> byLength = Ordering.natural()
    .nullsFirst()
    .onResultOf(String::length);

List<String> sorted = byLength.sortedCopy(list);
String longest = byLength.max(list);
List<String> top3 = Ordering.natural().greatestOf(numbers, 3); // 3 largest, descending
boolean ascending = Ordering.natural().isOrdered(list);
```

> [!TIP]
> On Java 8+, the JDK's `Comparator.comparing(...).thenComparing(...)` covers many `Ordering` use
> cases. Reach for `Ordering` when you need `leastOf`/`greatestOf` (partial sort), `isOrdered`, or
> `explicit(...)` (a fixed custom order).

---

## 6. Immutable Collections

Immutable collections are Guava's most widely used feature. They cannot be modified after
creation, which makes them inherently thread-safe, safe to share freely, and often more
memory-efficient than a wrapped mutable collection.

```java
import com.google.common.collect.*;

ImmutableList<String> list = ImmutableList.of("a", "b", "c");
ImmutableSet<Integer> set  = ImmutableSet.of(1, 2, 3);
ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1, "two", 2);

// Builders for larger or computed contents:
ImmutableList<String> built = ImmutableList.<String>builder()
    .add("a")
    .addAll(moreItems)
    .build();

// Copy from an existing collection:
ImmutableSet<String> copy = ImmutableSet.copyOf(someCollection);
```

Available immutable types include `ImmutableList`, `ImmutableSet`, `ImmutableSortedSet`,
`ImmutableMap`, `ImmutableSortedMap`, `ImmutableBiMap`, `ImmutableMultiset`, `ImmutableMultimap`
(and its list/set variants), and `ImmutableTable`.

> [!WARNING]
> Every factory and builder **rejects `null`** elements, keys, and values with a
> `NullPointerException`. Immutable collections do not permit nulls — by design.

> [!IMPORTANT]
> `ImmutableMap.of(...)` and the default builder reject **duplicate keys** with an
> `IllegalArgumentException`. If later entries should win, use
> `ImmutableMap.builder().put(...).buildKeepingLast()`. To make a duplicate an explicit error, use
> `buildOrThrow()` (the same behavior as `build()`).

### 6.1 Building from a stream (Java 8+)

Guava provides `Collector`s so you can build immutable collections from a stream pipeline:

```java
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;

ImmutableList<String> upper = names.stream()
    .map(String::toUpperCase)
    .collect(toImmutableList());

ImmutableSet<Integer> evens = numbers.stream()
    .filter(n -> n % 2 == 0)
    .collect(toImmutableSet());
```

---

## 7. New Collection Types

Guava adds collection types the JDK lacks. Each is backed by familiar interfaces.

### 7.1 `Multiset` — a set that counts duplicates

```java
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

Multiset<String> words = HashMultiset.create();
words.add("apple");
words.add("apple");
words.add("pear");

words.count("apple");       // 2
words.add("apple", 5);      // add 5 more in one call
words.elementSet();         // {apple, pear} — the distinct elements
words.size();               // total including duplicates
```

A multiset is ideal for histograms and frequency counts. Variants include `HashMultiset`,
`TreeMultiset`, `LinkedHashMultiset`, and `ImmutableMultiset`.

### 7.2 `Multimap` — multiple values per key

```java
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

Multimap<String, Integer> scores = ArrayListMultimap.create();
scores.put("ada", 90);
scores.put("ada", 95);
scores.put("bob", 70);

scores.get("ada");          // [90, 95] — a live List view
scores.keySet();            // {ada, bob}
scores.size();              // 3 (total key-value pairs)
Map<String, Collection<Integer>> asMap = scores.asMap();
```

Pick the implementation by the value-collection semantics you want:

| Implementation | Values per key | Notes |
|----------------|----------------|-------|
| `ArrayListMultimap` | `List` (ordered, duplicates) | General purpose |
| `LinkedHashMultimap` | insertion-ordered, no duplicate pairs | Predictable iteration |
| `HashMultimap` | `Set` (no duplicate pairs) | |
| `TreeMultimap` | sorted keys and values | |
| `ImmutableListMultimap` / `ImmutableSetMultimap` | immutable | Share freely |

### 7.3 `BiMap` — a map with unique values

```java
import com.google.common.collect.HashBiMap;
import com.google.common.collect.BiMap;

BiMap<String, Integer> ids = HashBiMap.create();
ids.put("ada", 1);
ids.inverse().get(1);       // "ada" — the inverse view
```

A `BiMap` enforces uniqueness of values as well as keys; `put`ting a value that already exists
throws `IllegalArgumentException` (use `forcePut` to override).

### 7.4 `Table` — a two-dimensional map

```java
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

Table<String, String, Integer> sales = HashBasedTable.create();
sales.put("Q1", "north", 100);
sales.put("Q1", "south", 80);

sales.get("Q1", "north");   // 100
sales.row("Q1");            // {north=100, south=80}
sales.column("north");      // {Q1=100}
```

### 7.5 `RangeSet` and `RangeMap` — intervals

```java
import com.google.common.collect.*;

RangeSet<Integer> ranges = TreeRangeSet.create();
ranges.add(Range.closed(1, 10));
ranges.add(Range.closed(20, 30));
ranges.contains(5);                 // true
ranges.add(Range.closed(8, 22));    // merges into [1..30]

Range<Integer> r = Range.closedOpen(0, 100); // [0, 100)
r.contains(99);                     // true
r.contains(100);                    // false
```

`Range` factories: `open`, `closed`, `closedOpen`, `openClosed`, `lessThan`, `atMost`,
`greaterThan`, `atLeast`, `all`, `singleton`. Ranges support `intersection`, `span`, `gap`,
`encloses`, and `isConnected`.

---

## 8. Collection Utilities

Static helper classes mirror the collection types: `Lists`, `Sets`, `Maps`, `Multimaps`,
`Multisets`, `Iterables`, `Iterators`, `Streams`, `Collections2`, `Queues`, `Tables`, and
`Comparators`.

### 8.1 Factory methods with type inference

```java
import com.google.common.collect.*;

List<String> names = Lists.newArrayList("ada", "bob");
Set<Integer> ids   = Sets.newHashSet(1, 2, 3);
Map<String, Integer> m = Maps.newHashMap();

ArrayList<String> sized = Lists.newArrayListWithExpectedSize(1000);
```

> [!NOTE]
> On Java 7+ the diamond operator (`new ArrayList<>()`) makes these factories less essential, but
> the `...WithExpectedSize` and `...WithCapacity` variants still earn their keep when you know the
> target size up front.

### 8.2 `Sets` algebra

```java
Set<Integer> a = ImmutableSet.of(1, 2, 3);
Set<Integer> b = ImmutableSet.of(2, 3, 4);

Sets.union(a, b);               // {1, 2, 3, 4}  (lazy view)
Sets.intersection(a, b);        // {2, 3}
Sets.difference(a, b);          // {1}
Sets.cartesianProduct(a, b);    // all ordered pairs
Sets.powerSet(a);               // all subsets
```

### 8.3 `Maps` transformations and diffs

```java
Map<String, Integer> lengths = Maps.toMap(names, String::length);   // keys -> f(key)
Map<String, String> byId = Maps.uniqueIndex(people, Person::id);    // value -> indexed by key

MapDifference<String, Integer> diff = Maps.difference(left, right);
diff.entriesOnlyOnLeft();
diff.entriesDiffering();
```

### 8.4 `Lists` helpers

```java
Lists.partition(bigList, 100);          // List of 100-element sublists
Lists.reverse(list);                    // reversed view
Lists.transform(list, String::trim);    // lazy transformed view
Lists.cartesianProduct(listA, listB);
Lists.charactersOf("hello");            // List<Character>
```

### 8.5 `Iterables` / `Iterators`

```java
import com.google.common.collect.Iterables;

Iterables.getFirst(list, "default");
Iterables.getLast(list);
Iterables.getOnlyElement(list);                 // throws if size != 1
Iterables.concat(list1, list2, list3);          // lazy
Iterables.partition(iterable, 50);
Iterables.frequency(iterable, target);
boolean any = Iterables.any(list, s -> s.isEmpty());
Iterable<String> filtered = Iterables.filter(list, s -> s.length() > 3);
```

### 8.6 `Streams` and `Multimaps`/`Multisets` helpers

```java
import com.google.common.collect.Streams;

Streams.stream(iterable);                       // Iterable -> Stream
Streams.zip(streamA, streamB, (a, b) -> a + b); // pairwise combine

// Group a list into a Multimap:
ImmutableListMultimap<Integer, String> byLen =
    Multimaps.index(words, String::length);

// Count occurrences into a Multiset, then read top counts:
Multiset<String> counts = HashMultiset.create(words);
Multisets.copyHighestCountFirst(counts);        // ordered by frequency
```

---

## 9. In-Memory Caching

`com.google.common.cache.CacheBuilder` builds a thread-safe, in-memory cache. A `LoadingCache`
additionally computes (and remembers) values on demand via a `CacheLoader`.

```java
import com.google.common.cache.*;
import java.util.concurrent.TimeUnit;

LoadingCache<String, User> users = CacheBuilder.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .recordStats()
    .build(new CacheLoader<String, User>() {
      @Override public User load(String id) {
        return database.lookupUser(id);   // called only on a miss
      }
    });

User u = users.getUnchecked("ada");       // loads on first call, cached after
CacheStats stats = users.stats();         // hitRate(), missCount(), ...
users.invalidate("ada");
```

Common `CacheBuilder` options:

| Method | Effect |
|--------|--------|
| `maximumSize(long)` | Evict least-recently-used entries past this count |
| `maximumWeight(long)` + `weigher(...)` | Bound by a custom weight instead of count |
| `expireAfterWrite(Duration/long, unit)` | Expire entries a fixed time after creation |
| `expireAfterAccess(Duration/long, unit)` | Expire entries a fixed time after last access |
| `refreshAfterWrite(Duration/long, unit)` | Asynchronously refresh stale entries |
| `weakKeys()` / `weakValues()` / `softValues()` | Allow GC to reclaim entries |
| `removalListener(...)` | Be notified when entries are removed |
| `recordStats()` | Enable hit/miss statistics |

> [!NOTE]
> Guava's own documentation marks `CacheBuilder` as **discouraged in favor of**
> [Caffeine](https://github.com/ben-manes/caffeine), a higher-performance cache with a similar API.
> Guava's cache remains fully supported and is a fine choice when you want to avoid an extra
> dependency, but consider Caffeine for new, performance-sensitive code.

---

## 10. Primitives

Per-primitive utility classes wrap the gaps in `java.lang`: `Ints`, `Longs`, `Doubles`, `Floats`,
`Shorts`, `Bytes`, `Chars`, `Booleans` (plus `SignedBytes`, `UnsignedBytes`, `UnsignedInts`,
`UnsignedLongs`). They share a consistent method set, illustrated here with `Ints`:

```java
import com.google.common.primitives.Ints;

Ints.max(2, 7, 1);                       // 7
Ints.min(intArray);                      // smallest in the array
Ints.contains(intArray, 5);              // membership test
Ints.indexOf(intArray, 5);
Ints.concat(arr1, arr2);                 // join primitive arrays
Ints.toArray(listOfIntegers);            // List<Integer> -> int[]
Ints.asList(1, 2, 3);                    // int[] -> List<Integer> view
Ints.constrainToRange(value, 0, 100);    // clamp
Ints.checkedCast(longValue);             // long -> int, throws if it overflows
Ints.saturatedCast(longValue);           // long -> int, clamps instead of overflowing
Ints.join(",", 1, 2, 3);                 // "1,2,3"
```

Immutable primitive arrays — `ImmutableIntArray`, `ImmutableLongArray`, `ImmutableDoubleArray` —
store primitives without boxing while remaining immutable.

---

## 11. Math

`IntMath`, `LongMath`, `BigIntegerMath`, and `DoubleMath` provide overflow-aware and
rounding-aware arithmetic. `Stats` and `Quantiles` compute descriptive statistics.

```java
import com.google.common.math.IntMath;
import com.google.common.math.Stats;
import com.google.common.math.Quantiles;
import java.math.RoundingMode;

IntMath.checkedAdd(Integer.MAX_VALUE, 1);     // throws ArithmeticException (overflow)
IntMath.saturatedAdd(Integer.MAX_VALUE, 1);   // Integer.MAX_VALUE (clamps)
IntMath.divide(7, 2, RoundingMode.CEILING);   // 4
IntMath.log2(1000, RoundingMode.UP);          // 10
IntMath.gcd(12, 18);                          // 6
IntMath.factorial(5);                         // 120
IntMath.isPrime(97);                          // true

Stats s = Stats.of(2, 4, 4, 4, 5, 5, 7, 9);
s.mean();                       // 5.0
s.populationStandardDeviation();
s.min(); s.max();

double median = Quantiles.median().compute(dataset);
double p95   = Quantiles.percentiles().index(95).compute(dataset);
Map<Integer, Double> quartiles = Quantiles.quartiles().indexes(1, 2, 3).compute(dataset);
```

> [!WARNING]
> `checkedAdd`, `checkedMultiply`, `checkedPow`, etc. throw `ArithmeticException` on overflow —
> use them when a silently-wrong result would be a bug. The `saturated*` variants clamp to
> `MIN_VALUE`/`MAX_VALUE` instead.

---

## 12. Hashing

`com.google.common.hash` offers strong, well-specified hash functions and the data structures that
build on them, with a consistent fluent API.

```java
import com.google.common.hash.*;
import java.nio.charset.StandardCharsets;

HashFunction sha256 = Hashing.sha256();
HashCode code = sha256.hashString("hello", StandardCharsets.UTF_8);
String hex = code.toString();           // lowercase hex

// Hash structured data with a Funnel:
HashCode h = Hashing.murmur3_128().newHasher()
    .putLong(id)
    .putString(name, StandardCharsets.UTF_8)
    .hash();
```

Available functions include `md5()`, `sha1()`, `sha256()`, `sha384()`, `sha512()`,
`murmur3_32()`, `murmur3_128()`, `sipHash24()`, `crc32()`, `crc32c()`, `adler32()`, and the
`hmacSha*` family.

> [!CAUTION]
> `md5()` and `sha1()` are provided for compatibility with existing systems but are
> **cryptographically broken**. Do not use them for security purposes — prefer `sha256()` or
> stronger. (Guava marks `md5()` and `sha1()` as deprecated for exactly this reason.)

### 12.1 `BloomFilter` — probabilistic membership

```java
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.StandardCharsets;

BloomFilter<String> seen = BloomFilter.create(
    Funnels.stringFunnel(StandardCharsets.UTF_8),
    1_000_000,      // expected insertions
    0.01);          // acceptable false-positive probability

seen.put("ada");
seen.mightContain("ada");   // true
seen.mightContain("zed");   // almost always false; never a false negative
```

> [!WARNING]
> `BloomFilter.readFrom(InputStream, Funnel)` reads a serialized filter whose size is encoded in
> the stream. Do **not** deserialize Bloom filters from untrusted input — a hostile stream can
> declare an enormous size and exhaust memory. Only read filters you produced yourself (this was
> reported as issue #8463).

---

## 13. I/O

The heart of `com.google.common.io` is the **source/sink** abstraction: a `ByteSource`/`CharSource`
is a re-readable supplier of input, and a `ByteSink`/`CharSink` is a re-writable destination. They
open and close streams for you.

```java
import com.google.common.io.*;
import java.io.File;
import java.nio.charset.StandardCharsets;

// Read a whole file as text:
String text = Files.asCharSource(new File("notes.txt"), StandardCharsets.UTF_8).read();

// Read lines:
ImmutableList<String> lines =
    Files.asCharSource(new File("notes.txt"), StandardCharsets.UTF_8).readLines();

// Write text (truncating):
Files.asCharSink(new File("out.txt"), StandardCharsets.UTF_8).write("hello");

// Copy and compare:
Files.copy(new File("a.bin"), new File("b.bin"));
boolean same = Files.equal(new File("a.bin"), new File("b.bin"));
```

`Files` (and the NIO-based `MoreFiles`, which works with `java.nio.file.Path`) cover reading,
writing, copying, moving, hashing, and traversal. Lower-level helpers:

| Helper | Purpose |
|--------|---------|
| `ByteStreams.copy(in, out)` / `toByteArray(in)` | Stream-to-stream and stream-to-array |
| `CharStreams.copy(...)` / `readLines(...)` | Character-stream equivalents |
| `Resources.getResource(name)` / `toByteArray(url)` | Read classpath resources |
| `BaseEncoding.base64()` / `base16()` / `base32()` | Encode/decode bytes ↔ text |
| `Closer` | Safely close a group of `Closeable`s, propagating the first failure |

```java
BaseEncoding.base64().encode(bytes);                 // standard Base64
byte[] back = BaseEncoding.base64().decode(encoded);
BaseEncoding.base16().lowerCase().encode(bytes);     // lowercase hex

// Hash a file directly through a ByteSource:
HashCode digest = Files.asByteSource(new File("a.bin")).hash(Hashing.sha256());
```

> [!NOTE]
> Some I/O features — particularly around file metadata — are tested primarily on Linux and may
> behave differently on other platforms. See the warnings in the Admin Guide.

---

## 14. Concurrency

### 14.1 `ListenableFuture` and `Futures`

A `ListenableFuture` is a `Future` you can attach completion callbacks to, enabling composition
without blocking.

```java
import com.google.common.util.concurrent.*;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;

ListeningExecutorService pool =
    MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(4));

ListenableFuture<User> future = pool.submit(() -> loadUser(id));

// Transform without blocking:
ListenableFuture<String> name = Futures.transform(future, User::name, directExecutor());

// React to completion:
Futures.addCallback(future, new FutureCallback<User>() {
  @Override public void onSuccess(User u) { handle(u); }
  @Override public void onFailure(Throwable t) { log(t); }
}, directExecutor());

// Combine many:
ListenableFuture<List<User>> all = Futures.allAsList(f1, f2, f3);
```

Useful `Futures` methods: `immediateFuture`, `immediateFailedFuture`, `transform`,
`transformAsync`, `catching`, `withTimeout`, `allAsList`, `successfulAsList`, `whenAllComplete`,
`whenAllSucceed`, and `submit`.

> [!TIP]
> Use `MoreExecutors.directExecutor()` for cheap, non-blocking callbacks that run on whatever
> thread completed the future. For anything that might block or take time, pass a real executor so
> you don't tie up the completing thread.

### 14.2 `Service` and `ServiceManager`

A `Service` models a component with a start/run/stop lifecycle. `ServiceManager` coordinates many
services as a group.

```java
import com.google.common.util.concurrent.*;

Service server = new AbstractIdleService() {
  @Override protected void startUp() { /* open ports */ }
  @Override protected void shutDown() { /* release resources */ }
};
server.startAsync().awaitRunning();
// ... later ...
server.stopAsync().awaitTerminated();

ServiceManager manager = new ServiceManager(ImmutableList.of(svcA, svcB, svcC));
manager.startAsync().awaitHealthy();
```

Base classes to extend: `AbstractIdleService` (no work between start and stop),
`AbstractExecutionThreadService` (runs a loop on its own thread), and `AbstractScheduledService`
(runs a task on a schedule).

### 14.3 Rate limiting, striped locks, and more

```java
import com.google.common.util.concurrent.*;

RateLimiter limiter = RateLimiter.create(20.0);  // 20 permits/second
limiter.acquire();                                // block until a permit is available
if (limiter.tryAcquire()) { /* non-blocking */ }

Striped<Lock> locks = Striped.lock(64);           // fine-grained locking by key
Lock lock = locks.get(key);

ThreadFactory factory = new ThreadFactoryBuilder()
    .setNameFormat("worker-%d")
    .setDaemon(true)
    .build();

AtomicLongMap<String> counters = AtomicLongMap.create();
counters.incrementAndGet("requests");
```

`Uninterruptibles` provides interruption-safe versions of common blocking calls
(`sleepUninterruptibly`, `getUninterruptibly`, `awaitUninterruptibly`, ...), and `Monitor` is a
richer alternative to `synchronized`/`Condition` built around boolean `Guard`s.

---

## 15. Networking

```java
import com.google.common.net.*;

// Domain names with public-suffix awareness:
InternetDomainName name = InternetDomainName.from("www.google.co.uk");
name.topPrivateDomain();        // google.co.uk
name.publicSuffix();            // co.uk
name.isUnderPublicSuffix();     // true

// IP addresses:
InetAddress ip = InetAddresses.forString("2001:db8::1");
InetAddresses.toAddrString(ip); // canonical short form

// host:port parsing:
HostAndPort hp = HostAndPort.fromString("example.com:8080");
hp.getHost();                   // "example.com"
hp.getPortOrDefault(80);        // 8080

// Typed media types (constants provided):
MediaType json = MediaType.JSON_UTF_8;
MediaType png  = MediaType.PNG;
```

URL escaping lives in `UrlEscapers`:

```java
UrlEscapers.urlPathSegmentEscaper().escape("a/b c");      // escape a path segment
UrlEscapers.urlFormParameterEscaper().escape("a=b&c");    // escape a query parameter
```

---

## 16. Escaping HTML, XML, and More

```java
import com.google.common.html.HtmlEscapers;
import com.google.common.xml.XmlEscapers;

HtmlEscapers.htmlEscaper().escape("<b>Tom & Jerry</b>");
// &lt;b&gt;Tom &amp; Jerry&lt;/b&gt;

XmlEscapers.xmlContentEscaper().escape("a < b & c");
XmlEscapers.xmlAttributeEscaper().escape("\"quoted\"");
```

All escapers implement the common `com.google.common.escape.Escaper` interface, so they share the
same `escape(String)` method.

> [!CAUTION]
> These escapers protect against well-formedness problems, not against the full range of injection
> attacks. For HTML output in a security context, prefer a dedicated context-aware sanitizer.

---

## 17. Reflection

```java
import com.google.common.reflect.*;

// Capture a full generic type (defeats erasure):
TypeToken<List<String>> token = new TypeToken<List<String>>() {};
token.getRawType();                 // List.class
token.resolveType(List.class.getTypeParameters()[0]); // String

// Scan the classpath:
ClassPath cp = ClassPath.from(getClass().getClassLoader());
for (ClassPath.ClassInfo info : cp.getTopLevelClasses("com.example.app")) {
  // info.getName(), info.load()
}
```

`Invokable` is a fluent wrapper over `Method`/`Constructor`, and `AbstractInvocationHandler`
simplifies writing dynamic proxies.

---

## 18. EventBus (Publish/Subscribe)

`EventBus` lets components communicate without referencing each other directly.

```java
import com.google.common.eventbus.*;

EventBus bus = new EventBus("app");

// A subscriber:
class OrderListener {
  @Subscribe public void onOrder(OrderPlaced event) {
    System.out.println("Order: " + event.id());
  }
}

bus.register(new OrderListener());
bus.post(new OrderPlaced("ORD-1"));     // delivered to matching @Subscribe methods
```

Use `AsyncEventBus(Executor)` to dispatch events on a background executor instead of the posting
thread.

> [!NOTE]
> Guava's own documentation marks `EventBus` as **discouraged in favor of** dependency injection
> and dedicated concurrency frameworks for new designs. It remains supported and is convenient for
> decoupling within a single process.

---

## 19. Graphs

`com.google.common.graph` models graph-structured data. There are three top-level interfaces:

| Interface | Edges carry | Use for |
|-----------|-------------|---------|
| `Graph<N>` | nothing | Plain node-and-edge graphs |
| `ValueGraph<N, V>` | a value per edge | Weighted/labeled edges |
| `Network<N, E>` | first-class edge objects | Parallel edges, edge identity |

```java
import com.google.common.graph.*;

MutableGraph<String> graph = GraphBuilder.directed()
    .allowsSelfLoops(false)
    .build();
graph.putEdge("a", "b");
graph.putEdge("a", "c");
graph.successors("a");          // [b, c]
graph.adjacentNodes("b");       // [a]

// Weighted edges:
MutableValueGraph<String, Integer> weighted = ValueGraphBuilder.undirected().build();
weighted.putEdgeValue("x", "y", 5);
weighted.edgeValueOrDefault("x", "y", 0);   // 5

// Traversal and analysis:
Iterable<String> bfs = Traverser.forGraph(graph).breadthFirst("a");
boolean cyclic = Graphs.hasCycle(graph);
Set<String> reachable = Graphs.reachableNodes(graph, "a");
```

Build immutable graphs with `GraphBuilder.directed().immutable()` (and the `ValueGraph`/`Network`
equivalents). `Traverser.forTree(...)` is the cycle-free variant for tree-shaped data.

---

## 20. Best Practices

- [x] **Prefer immutable collections** for fields, return values, and constants — they are
  thread-safe and document intent. Reach for a mutable type only when you actually mutate.
- [x] **Validate inputs at method entry** with `Preconditions`. Fail fast with a clear message.
- [x] **Avoid `@Beta` APIs in libraries.** Code annotated `@Beta` can change or disappear in any
  release. If your code is itself a library on others' classpaths, do not call `@Beta` APIs (or use
  the [Guava Beta Checker](https://github.com/google/guava-beta-checker) to enforce this).
- [x] **Prefer JDK equivalents where they exist.** On Java 8+, use `java.util.Optional`,
  `Comparator.comparing`, `Objects.equals/hash`, and the Streams API for the basics; use Guava for
  what the JDK still lacks (multimaps, immutable collections with non-null guarantees, ranges,
  caching, `ListenableFuture`, graphs, hashing).
- [x] **Use the right flavor.** `-android` for Android or Android-compatible libraries; `-jre`
  everywhere else. Never mix both on one classpath.
- [x] **Don't deserialize Guava objects from untrusted input.** Serialized forms are not stable
  across versions, and some types (notably `BloomFilter`) can be abused by hostile data.

> [!IMPORTANT]
> Guava's classes are **not designed to defend against a malicious caller**. Do not use them as a
> trust boundary between trusted and untrusted code.

---

## 21. Troubleshooting

### Error: `NullPointerException` when building an immutable collection

**Cause:** You passed a `null` element, key, or value to an `ImmutableList`/`ImmutableSet`/
`ImmutableMap` factory or builder. Immutable collections reject nulls by design.

**Solution:** Filter nulls first, or use a type that permits them (e.g. a `HashMap`) if you truly
need null values.

**Prevention:** Treat null as "absent" and model it with `Optional` instead of storing it.

### Error: `IllegalArgumentException: Multiple entries with same key`

**Cause:** You supplied duplicate keys to `ImmutableMap.of(...)` or `ImmutableMap.Builder.build()`.

**Solution:** Use `ImmutableMap.builder()....buildKeepingLast()` to let the last value win, or
deduplicate before building. To make the duplicate an explicit failure, `buildOrThrow()` is the
default `build()` behavior.

**Prevention:** When indexing a collection by a possibly-non-unique key, use a `Multimap` (via
`Multimaps.index`) rather than a `Map`.

### Error: `Gradle unable to resolve Guava` / `VariantSelectionByAttributesException`

**Cause:** A dependency-resolution conflict between the `-jre` and `-android` variants, often when
one part of the dependency graph requests the Android flavor and another requests JRE (reported as
issue #8398).

**Solution:** Pin a single flavor across your build (force `com.google.guava:guava:33.6.0-jre` or
the `-android` equivalent), and ensure transitive dependencies agree.

**Prevention:** Declare Guava explicitly at the version and flavor you want so the resolver does
not have to choose.

### Problem: `Suppliers.memoize()` causes thread pinning under virtual threads

**Cause:** The memoizing supplier synchronizes while computing the value; under Project Loom
virtual threads, holding a monitor across a blocking computation can pin the carrier thread
(reported as issue #7140).

**Solution:** Keep the memoized computation short and non-blocking, or use a structure that does
not hold a monitor across blocking work for hot paths on virtual threads.

### Problem: `Quantiles` is very slow on data with many duplicate values

**Cause:** The quantile selection algorithm degrades on datasets dominated by duplicate values
(reported as issue #3789).

**Solution:** Deduplicate or pre-aggregate before computing quantiles when your data has heavy
repetition, or compute on a representative sample.

### Problem: `com.google.common.io` behaves differently on Windows/macOS

**Cause:** Some I/O behaviors are validated primarily on Linux and may differ on other platforms.

**Solution:** Test platform-sensitive file operations on your target OS, and prefer the
`java.nio.file`-based `MoreFiles` for portable file handling.

---

## 22. FAQ

**Q: Which flavor should I use, `-jre` or `-android`?**
Use `-jre` for any standard JVM (server, desktop, build tools). Use `-android` for Android apps or
for libraries that must remain Android-compatible. The two differ only in the version suffix.

**Q: What is the minimum Java version?**
The JRE flavor requires JDK 1.8 or higher. The Android flavor targets Android (and is tested down
to API level 23).

**Q: Does Guava drag in lots of transitive dependencies?**
No. The only dependency needed at runtime is `com.google.guava:failureaccess:1.0.3`. The other
declared dependencies are annotation-only and do not add runtime weight.

**Q: What does the `@Beta` annotation mean?**
It marks an API that may change or be removed in any future release. Application code may use beta
APIs, but library code should avoid them (or use the Guava Beta Checker to enforce that).

**Q: Are deprecated APIs going to be removed?**
Generally no. Non-`@Beta` APIs remain binary-compatible indefinitely; even `@Deprecated`
non-`@Beta` APIs are kept. The last release to remove non-`@Beta` APIs was Guava 21.0.

**Q: Should I still use Guava's `Optional` now that `java.util.Optional` exists?**
Prefer `java.util.Optional` in new Java 8+ code. Keep Guava's `Optional` for interop with older
APIs; `toJavaUtil()` and `Optional.fromJavaUtil(...)` convert between the two.

**Q: Is Guava's cache the best choice for high-performance caching?**
Guava's documentation now points performance-sensitive users to
[Caffeine](https://github.com/ben-manes/caffeine), which has a similar API. Guava's `CacheBuilder`
remains supported and is a reasonable choice when you want to avoid an extra dependency.

**Q: Can I persist Guava objects by serializing them?**
Don't rely on it. Serialized forms of Guava objects are subject to change across versions and are
not guaranteed to be readable by a different version.

**Q: Is Guava safe to use as a security boundary?**
No. Guava's classes are not designed to protect against a malicious caller; do not use them between
trusted and untrusted code.

**Q: Where is the API documentation?**
At [guava.dev/api](https://guava.dev/api). You can also jump to any class by appending its name to
`guava.dev`, e.g. [guava.dev/ImmutableList](https://guava.dev/ImmutableList).

**Q: How do I build an immutable collection from a Java stream?**
Collect with `ImmutableList.toImmutableList()`, `ImmutableSet.toImmutableSet()`, or
`ImmutableMap.toImmutableMap(keyFn, valueFn)`.

---

_Generated June 2026 from google/guava at 9a5d60d. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
