---
title: Java SDK
url: https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java
description: Installiere und konfiguriere das Anthropic Java SDK mit Builder-Mustern und Async-Unterstützung
---

Das Anthropic Java SDK bietet bequemen Zugriff auf die Claude API aus Anwendungen, die in Java geschrieben sind. Es verwendet das „builder pattern" (Builder-Muster) zum Erstellen von Anfragen und unterstützt sowohl synchrone als auch asynchrone Operationen.

<Info>
  Eine Dokumentation der API-Funktionen mit Codebeispielen findest du in der [API-Referenz](https://platform.claude.com/docs/de/api/overview). Diese Seite behandelt Java-spezifische SDK-Funktionen und -Konfiguration.
</Info>

## Installation

<Tabs>
  <Tab title="Gradle">
    ```kotlin
    implementation("com.anthropic:anthropic-java:3.3.0")
    ```
  </Tab>

  <Tab title="Maven">
    ```xml
    <dependency>
        <groupId>com.anthropic</groupId>
        <artifactId>anthropic-java</artifactId>
        <version>3.3.0</version>
    </dependency>
    ```
  </Tab>
</Tabs>

## Anforderungen

Diese Bibliothek erfordert Java 8 oder höher.

<Note>
  Das SDK unterstützt Java 8 und höher. Die Codebeispiele in dieser Dokumentation sind als [JDK 25 Compact Source Files](https://openjdk.org/jeps/512) geschrieben und verwenden einen einfachen `void main()`-Einstiegspunkt sowie `IO.println()` für die Ausgabe. Die API-Aufrufe selbst sind auf jedem unterstützten JDK identisch; um ein Beispiel auf einer früheren Version zu kompilieren, ersetze `IO.println(...)` durch `System.out.println(...)` und platziere den Rumpf innerhalb von `public static void main(String[] args)` in einer Klasse.
</Note>

## Schnellstart

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

// Konfiguriert über die System-Properties `anthropic.apiKey`, `anthropic.authToken` und `anthropic.baseUrl`
// Oder konfiguriert über die Umgebungsvariablen `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` und `ANTHROPIC_BASE_URL`
AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

Message message = client.messages().create(params);
```

## Client-Konfiguration

### API-Key einrichten

Konfiguriere den Client über Systemeigenschaften oder Umgebungsvariablen:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

// Konfiguriert über die System-Properties `anthropic.apiKey`, `anthropic.authToken` und `anthropic.baseUrl`
// Oder konfiguriert über die Umgebungsvariablen `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` und `ANTHROPIC_BASE_URL`
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
```

Oder konfiguriere ihn manuell:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .apiKey("my-anthropic-api-key")
  .build();
```

Oder verwende eine Kombination beider Ansätze:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  // Konfiguriert über System-Properties oder Umgebungsvariablen
  .fromEnv()
  .apiKey("my-anthropic-api-key")
  .build();
```

Informationen zu Authentifizierungsoptionen, einschließlich Workload Identity Federation, findest du unter [Authentifizierung](https://platform.claude.com/docs/de/manage-claude/authentication). Wenn dein API-Key ein [persönlicher Key oder Service-Account-Key](https://platform.claude.com/docs/de/manage-claude/authentication#key-types) ist, der nicht auf einen Workspace beschränkt ist, setze die Workspace-ID im Request-Header `anthropic-workspace-id`; [Einen Workspace auswählen](https://platform.claude.com/docs/de/manage-claude/authentication#select-a-workspace) zeigt die Option pro Anfrage für dieses SDK.

### Konfigurationsoptionen

| Setter      | Systemeigenschaft     | Umgebungsvariable      | Erforderlich | Standardwert                  |
| ----------- | --------------------- | ---------------------- | ------------ | ----------------------------- |
| `apiKey`    | `anthropic.apiKey`    | `ANTHROPIC_API_KEY`    | false        | -                             |
| `authToken` | `anthropic.authToken` | `ANTHROPIC_AUTH_TOKEN` | false        | -                             |
| `baseUrl`   | `anthropic.baseUrl`   | `ANTHROPIC_BASE_URL`   | true         | `"https://api.anthropic.com"` |

Systemeigenschaften haben Vorrang vor Umgebungsvariablen.

<Tip>
  Erstelle nicht mehr als einen Client in derselben Anwendung. Jeder Client hat einen Verbindungspool und Thread-Pools, die effizienter sind, wenn sie zwischen Anfragen geteilt werden.
</Tip>

### Konfiguration ändern

Um vorübergehend eine geänderte Client-Konfiguration zu verwenden und dabei dieselben Verbindungs- und Thread-Pools wiederzuverwenden, rufe `withOptions()` auf einem beliebigen Client oder Service auf:

```java
import com.anthropic.client.AnthropicClient;

AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
  optionsBuilder.baseUrl("https://example.com");
  optionsBuilder.maxRetries(42);
});
```

Die Methode `withOptions()` wirkt sich nicht auf den ursprünglichen Client oder Service aus.

## Asynchrone Nutzung

Der Standard-Client ist synchron. Um zur asynchronen Ausführung zu wechseln, rufe die Methode `async()` auf:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.async().messages().create(params);
```

Oder erstelle von Anfang an einen asynchronen Client:

```java
import com.anthropic.client.AnthropicClientAsync;
import com.anthropic.client.okhttp.AnthropicOkHttpClientAsync;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClientAsync client = AnthropicOkHttpClientAsync.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.messages().create(params);
```

Der asynchrone Client unterstützt dieselben Optionen wie der synchrone, mit der Ausnahme, dass die meisten Methoden `CompletableFuture`s zurückgeben.

## Streaming

Das SDK definiert Methoden, die Streams von Antwort-„Chunks" zurückgeben, wobei jeder Chunk einzeln verarbeitet werden kann, sobald er eintrifft, anstatt auf die vollständige Antwort zu warten.

### Synchrones Streaming

Diese Streaming-Methoden geben für synchrone Clients `StreamResponse` zurück:

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

try (StreamResponse<RawMessageStreamEvent> streamResponse = client.messages().createStreaming(params)) {
    streamResponse.stream().forEach(chunk -> {
        IO.println(chunk);
    });
    IO.println("No more chunks!");
}
```

### Asynchrones Streaming

Für asynchrone Clients gibt die Methode `AsyncStreamResponse` zurück:

```java
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

client.async().messages().createStreaming(params).subscribe(chunk -> {
    IO.println(chunk);
});

// Falls du Fehler oder den Abschluss des Streams behandeln musst
client.async().messages().createStreaming(params).subscribe(new AsyncStreamResponse.Handler<>() {
    @Override
    public void onNext(RawMessageStreamEvent chunk) {
        IO.println(chunk);
    }

    @Override
    public void onComplete(Optional<Throwable> error) {
        if (error.isPresent()) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error.get());
        } else {
            IO.println("No more chunks!");
        }
    }
});

// Oder verwende Futures
client.async().messages().createStreaming(params)
    .subscribe(chunk -> {
        IO.println(chunk);
    })
    .onCompleteFuture()
    .whenComplete((unused, error) -> {
        if (error != null) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error);
        } else {
            IO.println("No more chunks!");
        }
    });
```

Asynchrones Streaming verwendet einen dedizierten, gecachten Thread-Pool-`Executor` pro Client, um zu streamen, ohne den aktuellen Thread zu blockieren. Um einen anderen `Executor` zu verwenden:

```java
Executor executor = Executors.newFixedThreadPool(4);
client.async().messages().createStreaming(params).subscribe(
    chunk -> IO.println(chunk), executor
);
```

Oder konfiguriere den Client global mit der Methode `streamHandlerExecutor`:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .streamHandlerExecutor(Executors.newFixedThreadPool(4))
  .build();
```

### Streaming mit Message Accumulator

Ein `MessageAccumulator` kann den Stream von Events in der Antwort aufzeichnen, während sie verarbeitet werden, und ein `Message`-Objekt akkumulieren, das dem ähnelt, was die Nicht-Streaming-API zurückgegeben hätte.

Für eine synchrone Antwort füge der Stream-Pipeline einen `Stream.peek()`-Aufruf hinzu, um jedes Event zu akkumulieren:

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.RawMessageStreamEvent;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

try (StreamResponse<RawMessageStreamEvent> streamResponse =
         client.messages().createStreaming(createParams)) {
    streamResponse.stream()
            .peek(messageAccumulator::accumulate)
            .flatMap(event -> event.contentBlockDelta().stream())
            .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
            .forEach(textDelta -> IO.print(textDelta.text()));
}

Message message = messageAccumulator.message();
```

Für eine asynchrone Antwort füge den `MessageAccumulator` dem `subscribe()`-Aufruf hinzu:

```java
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

client.async().messages()
        .createStreaming(createParams)
        .subscribe(event -> messageAccumulator.accumulate(event).contentBlockDelta().stream()
                .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
                .forEach(textDelta -> IO.print(textDelta.text())))
        .onCompleteFuture()
        .join();

Message message = messageAccumulator.message();
```

Ein `BetaMessageAccumulator` ist ebenfalls für die Akkumulation eines `BetaMessage`-Objekts verfügbar. Er wird auf die gleiche Weise wie der `MessageAccumulator` verwendet.

## Strukturierte Ausgaben

Die vollständige Dokumentation zu „structured outputs" (strukturierten Ausgaben) einschließlich Java-Beispielen findest du unter [Strukturierte Ausgaben](https://platform.claude.com/docs/de/build-with-claude/structured-outputs).

## Tool-Nutzung

Mit der [Tool-Nutzung mit Claude](https://platform.claude.com/docs/de/agents-and-tools/tool-use/overview) kannst du externe Tools und Funktionen direkt in die Antworten des KI-Modells integrieren. Anstatt reinen Text zu erzeugen, kann das Modell bei Bedarf Anweisungen (mit Parametern) zum Aufrufen eines Tools oder einer Funktion ausgeben. Du definierst JSON-Schemas für Tools, und das Modell verwendet die Schemas, um zu bestimmen, wann und wie diese Tools verwendet werden.

Die Tool-Nutzung unterstützt einen „strict"-Modus, der garantiert, dass die JSON-Ausgabe des KI-Modells dem JSON-Schema entspricht, das du in den Eingabeparametern angibst.

Das SDK kann ein Tool und seine Parameter automatisch aus der Struktur einer beliebigen Java-Klasse ableiten: Der Name der Klasse (in Snake Case umgewandelt) liefert den Tool-Namen, und die Felder der Klasse definieren die Parameter des Tools.

<Note>
  Deklariere deine Tool-Klassen als Top-Level-Klassen oder als `static` verschachtelte Klassen. Diese Anforderung stammt von der Jackson-Databind-Bibliothek (`com.fasterxml.jackson.databind`), die das SDK verwendet, um Tool-Eingaben in Instanzen deiner Klassen zu deserialisieren, und die keine nicht-statischen inneren Klassen instanziieren kann.
</Note>

### Tools mit Annotationen definieren

```java
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;

enum Unit {
  CELSIUS,
  FAHRENHEIT;

  public String toString() {
    return switch (this) {
      case CELSIUS -> "C";
      case FAHRENHEIT -> "F";
    };
  }

  public double fromKelvin(double temperatureK) {
    return switch (this) {
      case CELSIUS -> temperatureK - 273.15;
      case FAHRENHEIT -> (temperatureK - 273.15) * 1.8 + 32.0;
    };
  }
}

@JsonClassDescription("Get the weather in a given location")
static class GetWeather {

  @JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
  public String location;

  @JsonPropertyDescription("The unit of temperature")
  public Unit unit;

  public Weather execute() {
    double temperatureK = switch (location) {
      case "San Francisco, CA" -> 300.0;
      case "New York, NY" -> 310.0;
      case "Dallas, TX" -> 305.0;
      default -> 295;
    };
    return new Weather(String.format("%.0f%s", unit.fromKelvin(temperatureK), unit));
  }
}

static class Weather {

  public String temperature;

  public Weather(String temperature) {
    this.temperature = temperature;
  }
}
```

### Tools aufrufen

Wenn deine Tool-Klassen definiert sind, füge sie mit `MessageCreateParams.Builder.addTool(Class<T>)` zu den Nachrichtenparametern hinzu und rufe sie dann auf, wenn dies in der Antwort des KI-Modells angefordert wird. Mit `BetaToolUseBlock.input(Class<T>)` kannst du die Parameter eines Tools in JSON-Form in eine Instanz deiner Tool-definierenden Klasse parsen.

Verwende nach dem Aufruf des Tools `BetaToolResultBlockParam.Builder.contentAsJson(Object)`, um das Ergebnis des Tools an das KI-Modell zurückzugeben:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.messages.*;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
        .model(Model.CLAUDE_OPUS_5_5)
        .maxTokens(2048)
        .addTool(GetWeather.class)
        .addUserMessage("What's the temperature in New York?");

client.beta().messages().create(createParamsBuilder.build()).content().stream()
        .flatMap(contentBlock -> contentBlock.toolUse().stream())
        .forEach(toolUseBlock -> createParamsBuilder
              // Füge eine Nachricht hinzu, die angibt, dass die Tool-Nutzung angefordert wurde.
              .addAssistantMessageOfContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder()
                              .name(toolUseBlock.name())
                              .id(toolUseBlock.id())
                              .input(toolUseBlock._input())
                              .build())))
              // Füge eine Nachricht mit dem Ergebnis der angeforderten Tool-Nutzung hinzu.
              .addUserMessageOfContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolResult(BetaToolResultBlockParam.builder()
                              .toolUseId(toolUseBlock.id())
                              .contentAsJson(callTool(toolUseBlock))
                              .build()))));

client.beta().messages().create(createParamsBuilder.build()).content().stream()
        .flatMap(contentBlock -> contentBlock.text().stream())
        .forEach(textBlock -> IO.println(textBlock.text()));

private static Object callTool(BetaToolUseBlock toolUseBlock) {
  if (!"get_weather".equals(toolUseBlock.name())) {
    throw new IllegalArgumentException("Unknown tool: " + toolUseBlock.name());
  }

  GetWeather tool = toolUseBlock.input(GetWeather.class);
  return tool != null ? tool.execute() : new Weather("unknown");
}
```

### Umwandlung von Tool-Namen

Tool-Namen werden aus den Tool-Klassennamen in Camel Case (zum Beispiel `GetWeather`) abgeleitet und in Snake Case (zum Beispiel `get_weather`) umgewandelt. Wortgrenzen beginnen dort, wo das aktuelle Zeichen nicht das erste Zeichen ist, ein Großbuchstabe ist und entweder das vorhergehende Zeichen ein Kleinbuchstabe ist oder das folgende Zeichen ein Kleinbuchstabe ist. Zum Beispiel wird `MyJSONParser` zu `my_json_parser` und `ParseJSON` zu `parse_json`. Diese Umwandlung kann mit der Annotation `@JsonTypeName` überschrieben werden.

### Lokale JSON-Schema-Validierung für Tools

Du kannst eine lokale Validierung durchführen, um zu prüfen, ob das aus deiner Tool-Klasse abgeleitete JSON-Schema die Einschränkungen von Anthropic einhält. Die lokale Validierung ist standardmäßig aktiviert, kann aber deaktiviert werden:

```java
MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(2048)
  .addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
  .addUserMessage("What's the temperature in New York?");
```

### Tool-Klassen annotieren

Du kannst Annotationen verwenden, um den JSON-Schemas weitere Informationen über Tools hinzuzufügen:

* `@JsonClassDescription` - Fügt einer Tool-Klasse eine Beschreibung hinzu, die erläutert, wann und wie dieses Tool verwendet werden soll.
* `@JsonTypeName` - Setzt den Tool-Namen auf etwas anderes als den in Snake Case umgewandelten einfachen Namen der Klasse.
* `@JsonPropertyDescription` - Fügt einem Tool-Parameter eine detaillierte Beschreibung hinzu.
* `@JsonIgnore` - Schließt ein `public`-Feld oder eine Getter-Methode aus dem generierten JSON-Schema für die Parameter eines Tools aus.
* `@JsonProperty` - Schließt ein nicht-`public`-Feld oder eine Getter-Methode in das generierte JSON-Schema für die Parameter eines Tools ein.

## Message Batches

Das SDK bietet Unterstützung für [Batch-Verarbeitung](https://platform.claude.com/docs/de/build-with-claude/batch-processing) im Namespace `client.messages().batches()`. Unter [Paginierung](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#pagination) erfährst du, wie du Batches auflistest und durch sie paginierst.

## Datei-Uploads

Das SDK definiert Methoden, die Dateien über die Klasse `MultipartField` akzeptieren:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(Files.newInputStream(Paths.get("/path/to/file.pdf")))
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

Oder aus einem `InputStream`:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(URI.create("https://example.com/path/to/file").toURL().openStream())
      .filename("document.pdf")
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

Oder aus Bytes im Arbeitsspeicher:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(new ByteArrayInputStream("content".getBytes()))
      .filename("document.txt")
      .contentType("text/plain")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

### Binäre Antworten

Das SDK definiert Methoden, die binäre Antworten für API-Antworten zurückgeben, die nicht unbedingt als JSON geparst werden:

```java
import com.anthropic.core.http.HttpResponse;

HttpResponse response = client.files().download("file_abc123");
```

Um den Antwortinhalt in einer Datei zu speichern:

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    Files.copy(
        response.body(),
        Paths.get(path),
        StandardCopyOption.REPLACE_EXISTING
    );
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

Oder übertrage den Antwortinhalt in einen beliebigen `OutputStream`:

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    response.body().transferTo(Files.newOutputStream(Paths.get(path)));
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

## Fehlerbehandlung

Das SDK wirft benutzerdefinierte ungeprüfte Exception-Typen:

* `AnthropicServiceException` - Basisklasse für HTTP-Fehler.
* `AnthropicIoException` - I/O-Netzwerkfehler.
* `AnthropicRetryableException` - Generischer Fehler, der auf einen Fehlschlag hinweist, der wiederholt werden könnte.
* `AnthropicInvalidDataException` - Fehler beim Interpretieren erfolgreich geparster Daten (zum Beispiel beim Zugriff auf eine Eigenschaft, die eigentlich erforderlich sein sollte, die die API aber unerwartet weggelassen hat).
* `AnthropicException` - Basisklasse für alle Exceptions.

### Zuordnung von Statuscodes

| Status | Exception                       |
| ------ | ------------------------------- |
| 400    | `BadRequestException`           |
| 401    | `UnauthorizedException`         |
| 403    | `PermissionDeniedException`     |
| 404    | `NotFoundException`             |
| 422    | `UnprocessableEntityException`  |
| 429    | `RateLimitException`            |
| 5xx    | `InternalServerException`       |
| andere | `UnexpectedStatusCodeException` |

`SseException` wird bei Fehlern geworfen, die während des SSE-Streamings nach einer erfolgreichen initialen HTTP-Antwort auftreten.

```java
import com.anthropic.errors.*;

try {
    Message message = client.messages().create(params);
} catch (RateLimitException e) {
    IO.println("Rate limited, retry after: " + e.headers());
} catch (UnauthorizedException e) {
    IO.println("Invalid API key");
} catch (AnthropicServiceException e) {
    IO.println("API error: " + e.statusCode());
} catch (AnthropicIoException e) {
    IO.println("Network error: " + e.getMessage());
}
```

## Request-IDs

Wenn du [Rohantworten](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#raw-response-access) verwendest, kannst du mit der Methode `requestId()` auf den Antwort-Header `request-id` zugreifen:

```java
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

Optional<String> requestId = message.requestId();
```

Damit kannst du fehlgeschlagene Anfragen schnell protokollieren und an Anthropic melden. Weitere Informationen zum Debuggen von Anfragen findest du unter [Request-ID](https://platform.claude.com/docs/de/api/errors#request-id).

## Wiederholungsversuche

Das SDK wiederholt Anfragen standardmäßig automatisch 2 Mal, mit einem kurzen exponentiellen Backoff zwischen den Anfragen.

Nur die folgenden Fehlertypen werden wiederholt:

* Verbindungsfehler (zum Beispiel aufgrund eines Netzwerkverbindungsproblems)
* 408 Request Timeout
* 409 Conflict
* 429 Rate Limit
* 5xx Internal

Die API kann das SDK auch explizit anweisen, eine Anfrage zu wiederholen oder nicht zu wiederholen.

Um eine benutzerdefinierte Anzahl von Wiederholungsversuchen festzulegen, konfiguriere den Client mit der Methode `maxRetries`:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder().fromEnv().maxRetries(4).build();
```

## Timeouts

Anfragen laufen standardmäßig nach 10 Minuten in ein Timeout.

Bei Methoden, die `maxTokens` akzeptieren, wird das Standard-Timeout jedoch dynamisch mit dieser Formel berechnet, wenn du einen großen `maxTokens`-Wert angibst und Streaming verwendest:

```java
Duration.ofSeconds(
    Math.min(
        60 * 60, // 1 hour max
        Math.max(
            10 * 60, // 10 minute minimum
            60 * 60 * maxTokens / 128_000
        )
    )
)
```

Dies ergibt ein Timeout von bis zu 60 Minuten, skaliert anhand des Parameters `maxTokens`, sofern es nicht überschrieben wird.

Bei Nicht-Streaming-Anfragen skaliert das dynamische Timeout basierend auf `maxTokens` von mindestens 30 Sekunden bis maximal 10 Minuten.

Um ein benutzerdefiniertes Timeout pro Anfrage festzulegen:

```java
import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());
```

Oder konfiguriere den Standardwert für alle Methodenaufrufe auf Client-Ebene:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .timeout(Duration.ofSeconds(30))
  .build();
```

## Lange Anfragen

<Warning>
  Erwäge die Verwendung von [Streaming](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#streaming) für länger laufende Anfragen.
</Warning>

Vermeide es, einen großen `maxTokens`-Wert festzulegen, ohne Streaming zu verwenden. Einige Netzwerke trennen inaktive Verbindungen nach einer bestimmten Zeit, was dazu führen kann, dass die Anfrage fehlschlägt oder in ein [Timeout](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#timeouts) läuft, ohne eine Antwort von Anthropic zu erhalten. Das SDK pingt die API regelmäßig an, um die Verbindung aufrechtzuerhalten und die Auswirkungen dieser Netzwerke zu verringern.

Das SDK wirft einen Fehler, wenn erwartet wird, dass eine Nicht-Streaming-Anfrage länger als 10 Minuten dauert. Die Verwendung einer [Streaming-Methode](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#streaming) oder das [Überschreiben des Timeouts](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#timeouts) auf Client- oder Anfrageebene deaktiviert den Fehler.

## Paginierung

Das SDK bietet bequeme Möglichkeiten, auf paginierte Ergebnisse zuzugreifen, entweder Seite für Seite oder Element für Element über alle Seiten hinweg.

### Automatische Paginierung

Um alle Ergebnisse über alle Seiten hinweg zu durchlaufen, verwende die Methode `autoPager()`, die bei Bedarf automatisch weitere Seiten abruft.

```java
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;

BatchListPage page = client.messages().batches().list();

// Als Iterable verarbeiten
for (MessageBatch batch : page.autoPager()) {
    IO.println(batch);
}

// Als Stream verarbeiten
page.autoPager()
    .stream()
    .limit(50)
    .forEach(batch -> IO.println(batch));
```

Bei Verwendung des asynchronen Clients gibt die Methode eine `AsyncStreamResponse` zurück:

```java
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.batches.BatchListPageAsync;
import com.anthropic.models.messages.batches.MessageBatch;

CompletableFuture<BatchListPageAsync> pageFuture = client.async().messages().batches().list();

pageFuture.thenAccept(page -> page.autoPager().subscribe(batch -> {
    IO.println(batch);
}));

// Falls du Fehler oder den Abschluss des Streams behandeln musst
pageFuture.thenAccept(page -> page.autoPager().subscribe(new AsyncStreamResponse.Handler<>() {
    @Override
    public void onNext(MessageBatch batch) {
        IO.println(batch);
    }

    @Override
    public void onComplete(Optional<Throwable> error) {
        if (error.isPresent()) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error.get());
        } else {
            IO.println("No more!");
        }
    }
}));

// Oder verwende Futures
pageFuture.thenAccept(page -> page.autoPager()
    .subscribe(batch -> {
        IO.println(batch);
    })
    .onCompleteFuture()
    .whenComplete((unused, error) -> {
        if (error != null) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error);
        } else {
            IO.println("No more!");
        }
    }));
```

### Manuelle Paginierung

Um auf einzelne Seitenelemente zuzugreifen und die nächste Seite manuell anzufordern:

```java
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;

BatchListPage page = client.messages().batches().list();
while (true) {
    for (MessageBatch batch : page.items()) {
        IO.println(batch);
    }

    if (!page.hasNextPage()) {
        break;
    }

    page = page.nextPage();
}
```

## Typsystem

### Unveränderlichkeit und Builder

Jede Klasse im SDK hat einen zugehörigen Builder zu ihrer Konstruktion. Jede Klasse ist nach der Konstruktion unveränderlich. Wenn die Klasse einen zugehörigen Builder hat, besitzt sie eine Methode `toBuilder()`, mit der sie wieder in einen Builder umgewandelt werden kann, um eine geänderte Kopie zu erstellen.

```java
MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

// Erstelle eine geänderte Kopie mit toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();
```

Da jede Klasse unveränderlich ist, wirkt sich eine Änderung am Builder niemals auf bereits erstellte Klasseninstanzen aus.

### Anfragen und Antworten

Um eine Anfrage an die Claude API zu senden, erstelle eine Instanz einer `Params`-Klasse und übergib sie an die entsprechende Client-Methode. Wenn die Antwort empfangen wird, wird sie in eine Instanz einer Java-Klasse deserialisiert.

Zum Beispiel sollte `client.messages().create(...)` mit einer Instanz von `MessageCreateParams` aufgerufen werden und gibt eine Instanz von `Message` zurück.

### Undokumentierte Parameter

Um undokumentierte Parameter festzulegen, rufe die Methoden `putAdditionalHeader`, `putAdditionalQueryParam` oder `putAdditionalBodyProperty` auf einer beliebigen `Params`-Klasse auf:

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .putAdditionalHeader("Secret-Header", "42")
  .putAdditionalQueryParam("secret_query_param", "42")
  .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))
  .build();
```

Auf diese kann später am erstellten Objekt über die Methoden `_additionalHeaders()`, `_additionalQueryParams()` und `_additionalBodyProperties()` zugegriffen werden.

<Warning>
  Die an diese Methoden übergebenen Werte überschreiben Werte, die an frühere Methoden übergeben wurden. Stelle aus Sicherheitsgründen sicher, dass diese Methoden nur mit vertrauenswürdigen Eingabedaten verwendet werden.
</Warning>

Um undokumentierte Parameter für verschachtelte Header-, Query-Parameter- oder Body-Klassen festzulegen:

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Metadata;

MessageCreateParams params = MessageCreateParams.builder()
  .metadata(
    Metadata.builder().putAdditionalProperty("secretProperty", JsonValue.from("42")).build()
  )
  .build();
```

Auf diese Eigenschaften kann später am verschachtelten erstellten Objekt über die Methode `_additionalProperties()` zugegriffen werden.

Um einen dokumentierten Parameter oder eine dokumentierte Eigenschaft auf einen undokumentierten oder noch nicht unterstützten Wert zu setzen, übergib ein `JsonValue`-Objekt an den entsprechenden Setter:

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(JsonValue.from(3.14))
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();
```

### JsonValue erstellen

Der einfachste Weg, ein `JsonValue` zu erstellen, ist die Verwendung seiner Methode `from(...)`:

```java
import com.anthropic.core.JsonValue;

// Erstelle primitive JSON-Werte
JsonValue nullValue = JsonValue.from(null);

JsonValue booleanValue = JsonValue.from(true);

JsonValue numberValue = JsonValue.from(42);

JsonValue stringValue = JsonValue.from("Hello World!");

// Erstelle einen JSON-Array-Wert, der `["Hello", "World"]` entspricht
JsonValue arrayValue = JsonValue.from(List.of("Hello", "World"));

// Erstelle einen JSON-Objekt-Wert, der `{ "a": 1, "b": 2 }` entspricht
JsonValue objectValue = JsonValue.from(Map.of("a", 1, "b", 2));

// Erstelle beliebig verschachteltes JSON, das Folgendem entspricht:
// { "a": [1, 2], "b": [3, 4] }
JsonValue complexValue = JsonValue.from(Map.of("a", List.of(1, 2), "b", List.of(3, 4)));
```

### Erforderliche Parameter erzwungen weglassen

Normalerweise wirft die `build`-Methode einer `Builder`-Klasse eine `IllegalStateException`, wenn ein erforderlicher Parameter oder eine erforderliche Eigenschaft nicht gesetzt ist. Um einen erforderlichen Parameter oder eine erforderliche Eigenschaft erzwungen wegzulassen, übergib `JsonMissing`:

```java
import com.anthropic.core.JsonMissing;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .addUserMessage("Hello, world")
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(JsonMissing.of())
  .build();
```

### Antworteigenschaften

Um auf undokumentierte Antworteigenschaften zuzugreifen, rufe die Methode `_additionalProperties()` auf:

```java
import com.anthropic.core.JsonValue;

Map<String, JsonValue> additionalProperties = client
  .messages()
  .create(params)
  ._additionalProperties();

JsonValue secretPropertyValue = additionalProperties.get("secretProperty");

String result = secretPropertyValue.accept(new JsonValue.Visitor<>() {
    @Override
    public String visitNull() {
        return "It's null!";
    }

    @Override
    public String visitBoolean(boolean value) {
        return "It's a boolean!";
    }

    @Override
    public String visitNumber(Number value) {
        return "It's a number!";
    }

    // Weitere Methoden sind `visitMissing`, `visitString`, `visitArray` und `visitObject`
    // Die Standardimplementierung jeder nicht implementierten Methode delegiert an `visitDefault`,
    // das standardmäßig eine Exception wirft, aber auch überschrieben werden kann
});
```

Um auf den rohen JSON-Wert einer Eigenschaft zuzugreifen, rufe ihre mit `_` präfixierte Methode auf:

```java
import com.anthropic.core.JsonField;
import com.anthropic.models.messages.StopReason;

JsonField<StopReason> stopReason = client.messages().create(params)._stopReason();

if (stopReason.isMissing()) {
  // Die Eigenschaft fehlt in der JSON-Antwort
} else if (stopReason.isNull()) {
  // Die Eigenschaft wurde auf das Literal null gesetzt
} else {
  // Prüfe, ob der Wert als String übergeben wurde
  // Weitere Methoden sind `asNumber()`, `asBoolean()` usw.
  Optional<String> jsonString = stopReason.asString();

  // Versuche, in einen benutzerdefinierten Typ zu deserialisieren
  MyClass myObject = stopReason.asUnknown().orElseThrow().convert(MyClass.class);
}
```

### Antwortvalidierung

Standardmäßig wirft das SDK keine Exception, wenn die API eine Antwort zurückgibt, die nicht dem erwarteten Typ entspricht. Es wirft `AnthropicInvalidDataException` nur, wenn du direkt auf die Eigenschaft zugreifst.

Um vorab zu prüfen, ob die Antwort vollständig korrekt typisiert ist, rufe `validate()` auf:

```java
import com.anthropic.models.messages.Message;

Message message = client.messages().create(params).validate();
```

Oder konfiguriere es pro Anfrage:

```java
import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().responseValidation(true).build());
```

Oder konfiguriere den Standardwert für alle Methodenaufrufe auf Client-Ebene:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .responseValidation(true)
  .build();
```

## Anpassung des HTTP-Clients

### Proxy-Konfiguration

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import java.net.Proxy;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("https://example.com", 8080)))
  .build();
```

### HTTPS-/SSL-Konfiguration

<Note>
  Die meisten Anwendungen sollten diese Methoden nicht aufrufen und stattdessen die Systemstandards verwenden. Die Standards enthalten spezielle Optimierungen, die verloren gehen können, wenn die Implementierungen geändert werden.
</Note>

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .sslSocketFactory(yourSSLSocketFactory)
  .trustManager(yourTrustManager)
  .hostnameVerifier(yourHostnameVerifier)
  .build();
```

### Benutzerdefinierter HTTP-Client

Das SDK besteht aus drei Artefakten:

* `anthropic-java-core` - Enthält die Kernlogik des SDK und hängt nicht von OkHttp ab. Stellt `AnthropicClient`, `AnthropicClientAsync` und deren Implementierungsklassen bereit, die alle mit jedem HTTP-Client funktionieren.
* `anthropic-java-client-okhttp` - Hängt von OkHttp ab. Stellt `AnthropicOkHttpClient` und `AnthropicOkHttpClientAsync` bereit.
* `anthropic-java` - Hängt von den APIs von `anthropic-java-core` und `anthropic-java-client-okhttp` ab und stellt diese bereit. Hat keine eigene Logik.

Diese Struktur ermöglicht es, den Standard-HTTP-Client des SDK zu ersetzen, ohne unnötige Abhängigkeiten einzubinden.

#### Angepasster OkHttpClient

<Tip>
  Probiere die verfügbaren [Netzwerkoptionen](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#retries) aus, bevor du den Standard-Client ersetzt.
</Tip>

Um einen angepassten `OkHttpClient` zu verwenden:

1. Ersetze deine `anthropic-java`-Abhängigkeit durch `anthropic-java-core`.
2. Kopiere die Klasse `OkHttpClient` aus `anthropic-java-client-okhttp` in deinen Code und passe sie an.
3. Konstruiere `AnthropicClientImpl` oder `AnthropicClientAsyncImpl` mit deinem angepassten Client.

#### Vollständig benutzerdefinierter HTTP-Client

Um einen vollständig benutzerdefinierten HTTP-Client zu verwenden:

1. Ersetze deine `anthropic-java`-Abhängigkeit durch `anthropic-java-core`.
2. Schreibe eine Klasse, die das Interface `HttpClient` implementiert.
3. Konstruiere `AnthropicClientImpl` oder `AnthropicClientAsyncImpl` mit deiner neuen Client-Klasse.

## Plattformintegrationen

<Note>
  Detaillierte Anleitungen zur Plattformeinrichtung mit Codebeispielen findest du unter:

  * [Amazon Bedrock](https://platform.claude.com/docs/de/build-with-claude/claude-in-amazon-bedrock)
  * [Amazon Bedrock (Opus 4.6 und früher)](https://platform.claude.com/docs/de/build-with-claude/claude-on-amazon-bedrock-legacy)
  * [Claude Platform on AWS](https://platform.claude.com/docs/de/build-with-claude/claude-platform-on-aws)
  * [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/de/build-with-claude/claude-models-on-google-cloud/google-managed)
  * [Microsoft Foundry](https://platform.claude.com/docs/de/build-with-claude/claude-in-microsoft-foundry)

  Siehe auch [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/de/build-with-claude/claude-models-on-google-cloud/anthropic-managed).
</Note>

Das Java SDK unterstützt die folgenden Plattformen über separate Abhängigkeiten, die plattformspezifische `Backend`-Implementierungen bereitstellen:

* **Agent Platform:** `com.anthropic:anthropic-java-vertex`: Verwende `VertexBackend.builder()` oder `VertexBackend.fromEnv()`. `fromEnv()` liest `CLOUD_ML_REGION` und `ANTHROPIC_VERTEX_PROJECT_ID` und verwendet Application Default Credentials.
* **Bedrock:** `com.anthropic:anthropic-java-bedrock`: Verwende `BedrockMantleBackend.fromEnv()` oder `BedrockMantleBackend.builder()` für den Messages-API-Bedrock-Endpunkt oder `BedrockBackend.fromEnv()` / `BedrockBackend.builder()` (`bedrock-runtime`-Pfad).
* **Claude Platform on AWS:** `com.anthropic:anthropic-java-aws`: Verwende `AwsBackend.fromEnv()` (liest `ANTHROPIC_AWS_WORKSPACE_ID` sowie die AWS-Standardregion/-Credential-Chain) oder `AwsBackend.builder()`. In der Beta verfügbar.
* **Foundry:** `com.anthropic:anthropic-java-foundry`: Verwende `FoundryBackend.fromEnv()` oder `FoundryBackend.builder()`.

Verwende `BedrockMantleBackend` für neue Projekte; `BedrockBackend` bleibt für bestehende Anwendungen erhalten, die die Bedrock-`InvokeModel`-API verwenden.

Das Java SDK unterstützt Claude Models on Google Cloud (Anthropic managed) auch über `GoogleCloudBackend` aus der Abhängigkeit `com.anthropic:anthropic-java-google-cloud`. Dieses Backend befindet sich in der Beta-Phase. Erstelle es mit `GoogleCloudBackend.builder()` oder `GoogleCloudBackend.fromEnv()`. `fromEnv()` liest `ANTHROPIC_GOOGLE_CLOUD_WORKSPACE_ID`, `ANTHROPIC_GOOGLE_CLOUD_PROJECT` und die Google Application Default Credentials. Siehe [Auflösung von Projekt, Standort und Workspace](https://platform.claude.com/docs/de/build-with-claude/claude-models-on-google-cloud/anthropic-managed#project-location-and-workspace-resolution).

Die Plattform-Artefakte sind Add-ons zur Basisabhängigkeit `com.anthropic:anthropic-java`, die `AnthropicOkHttpClient` bereitstellt, installiere also beide. Jede `Backend`-Implementierung wird mit `.backend()` auf `AnthropicOkHttpClient.builder()` an den Client übergeben. Jedes Cloud-Backend bindet die Klassen des jeweiligen Cloud-Plattform-SDK als transitive Abhängigkeiten ein.

## Erweiterte Nutzung

### Zugriff auf Rohantworten

Um auf HTTP-Header, Statuscodes und den rohen Antwort-Body zuzugreifen, stelle jedem HTTP-Methodenaufruf `withRawResponse()` voran:

```java
import com.anthropic.core.http.Headers;
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

int statusCode = message.statusCode();

Headers headers = message.headers();
```

Du kannst die Antwort bei Bedarf trotzdem in eine Instanz einer Java-Klasse deserialisieren:

```java
import com.anthropic.models.messages.Message;

Message parsedMessage = message.parse();
```

### Logging

Das SDK verwendet den Standard-Logging-Interceptor von OkHttp.

Aktiviere das Logging, indem du die Umgebungsvariable `ANTHROPIC_LOG` auf `info` setzt:

```bash
export ANTHROPIC_LOG=info
```

Oder auf `debug` für ausführlicheres Logging:

```bash
export ANTHROPIC_LOG=debug
```

<Accordion title="Jackson-Kompatibilität">
  Das SDK hängt für die JSON-Serialisierung/-Deserialisierung von Jackson ab. Es ist mit Version 2.13.4 oder höher kompatibel, hängt aber standardmäßig von Version 2.19.4 ab.

  Das SDK wirft eine Exception, wenn es zur Laufzeit eine inkompatible Jackson-Version erkennt (zum Beispiel, wenn die Standardversion in deiner Maven- oder Gradle-Konfiguration überschrieben wurde).

  Wenn das SDK eine Exception geworfen hat, du aber sicher bist, dass die Version kompatibel ist, deaktiviere die Versionsprüfung mit `checkJacksonVersionCompatibility` auf `AnthropicOkHttpClient` oder `AnthropicOkHttpClientAsync`.

  <Warning>
    Es gibt keine Garantie, dass das SDK korrekt funktioniert, wenn die Jackson-Versionsprüfung deaktiviert ist.
  </Warning>

  Es gibt außerdem Bugs in älteren Jackson-Versionen, die das SDK beeinträchtigen können. Das SDK umgeht nicht alle Jackson-Bugs und erwartet stattdessen, dass Nutzer Jackson dafür aktualisieren.
</Accordion>

<Accordion title="ProGuard/R8-Konfiguration">
  Obwohl das SDK Reflection verwendet, ist es dennoch mit ProGuard und R8 nutzbar, da `anthropic-java-core` mit einer Konfigurationsdatei veröffentlicht wird, die Keep-Regeln enthält.

  ProGuard und R8 sollten die veröffentlichten Regeln automatisch erkennen und verwenden, du kannst die Keep-Regeln bei Bedarf aber auch manuell kopieren.
</Accordion>

### OpenTelemetry-Tracing

Wenn deine Anwendung einen OpenTelemetry Tracer Provider registriert, gibt das SDK für jede Anfrage, die es sendet, einen Span aus. Um die Spans an deine Observability-Plattform zu senden, siehe [OpenTelemetry mit dem Claude SDK einrichten](https://platform.claude.com/docs/de/manage-claude/opentelemetry/sdk).

### Undokumentierte API-Funktionalität

Das SDK ist für die bequeme Nutzung der dokumentierten API typisiert. Es unterstützt jedoch auch die Arbeit mit undokumentierten oder noch nicht unterstützten Teilen der API.

#### Undokumentierte Anfrageparameter

Um undokumentierte Anfrageparameter festzulegen, verwende die Methoden `putAdditionalHeader`, `putAdditionalQueryParam` oder `putAdditionalBodyProperty`, wie unter [Undokumentierte Parameter](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#undocumented-parameters) beschrieben.

#### Undokumentierte Antworteigenschaften

Um auf undokumentierte Antworteigenschaften zuzugreifen, verwende die Methode `_additionalProperties()`, wie unter [Antworteigenschaften](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#response-properties) beschrieben.

#### Neue oder unveröffentlichte Enum-Werte

Enum-ähnliche Klassen im SDK, wie `Model` und `AnthropicBeta`, sind keine geschlossenen Java-`enum`-Typen. Jede bietet eine Factory-Methode `of(String)`, die einen beliebigen String akzeptiert, sodass du Werte verwenden kannst, die dem SDK noch nicht hinzugefügt wurden, etwa ein Modell oder einen Beta-Header, der nach deiner SDK-Version veröffentlicht wurde:

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.messages.Model;

Model model = Model.of("some-new-model");
AnthropicBeta beta = AnthropicBeta.of("some-new-beta-2026-01-01");
```

Builder-Methoden, die diese Typen entgegennehmen, bieten oft auch eine `String`-Überladung, die `of(...)` für dich aufruft:

```java
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .model("some-new-model") // same as .model(Model.of("some-new-model"))
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .build();
```

Bevorzuge die korrekt typisierten Konstanten (zum Beispiel `Model.CLAUDE_OPUS_5`), damit du Autovervollständigung und Abkündigungswarnungen erhältst. Die `String`-Überladungen und `of(...)` dienen in erster Linie dazu, das Feld auf einen undokumentierten oder noch nicht unterstützten Wert zu setzen, während du auf ein SDK-Release wartest, das ihn enthält.

## Beta-Funktionen

Beta-Funktionen sind vor der allgemeinen Veröffentlichung verfügbar, um frühes Feedback zu erhalten und neue Funktionalität zu testen. Die Verfügbarkeit aller Fähigkeiten und Tools von Claude kannst du in der [Funktionsübersicht](https://platform.claude.com/docs/de/build-with-claude/overview) prüfen.

Auf die meisten Beta-API-Funktionen kannst du über die Methode `beta()` auf dem Client zugreifen. Um eine bestimmte Beta-Funktion zu aktivieren, füge beim Erstellen der Nachrichtenparameter den entsprechenden [Beta-Header](https://platform.claude.com/docs/de/api/beta-headers) mit `.addBeta()` hinzu.

Zum Beispiel, um [Context Editing](https://platform.claude.com/docs/de/build-with-claude/context-editing) zu aktivieren:

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.beta.messages.BetaMessage;
import com.anthropic.models.beta.messages.MessageCreateParams;
// ...
void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    BetaMessage message = client.beta().messages().create(
        MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024L)
            .addBeta(AnthropicBeta.CONTEXT_MANAGEMENT_2025_06_27)
            .addUserMessage("Hello, Claude")
            .build());
}
```

## Häufig gestellte Fragen

<AccordionGroup>
  <Accordion title="Warum verwendet das SDK keine einfachen Enum-Klassen?">
    Java-`enum`-Klassen sind nicht ohne Weiteres vorwärtskompatibel. Ihre Verwendung im SDK könnte zu Laufzeit-Exceptions führen, wenn die API aktualisiert wird und mit einem neuen Enum-Wert antwortet.

    Da diese Klassen offen sind, kannst du sie auch über ihre Factory-Methode `of(String)` mit einem beliebigen String-Wert konstruieren. Siehe [Neue oder unveröffentlichte Enum-Werte](https://platform.claude.com/docs/de/cli-sdks-libraries/sdks/java#new-or-unreleased-enum-values), wenn du einen Wert verwenden musst, der in deiner SDK-Version noch nicht enthalten ist.
  </Accordion>

  <Accordion title="Warum werden Felder mit JsonField<T> statt einfach mit T dargestellt?">
    Die Verwendung von `JsonField<T>` ermöglicht einige Funktionen:

    * Nutzung undokumentierter API-Funktionalität
    * Verzögerte Validierung der API-Antwort gegen die erwartete Struktur
    * Unterscheidung zwischen fehlenden und explizit auf null gesetzten Werten
  </Accordion>

  <Accordion title="Warum verwendet das SDK keine Data Classes?">
    Das Hinzufügen neuer Felder zu einer Data Class ist nicht abwärtskompatibel, und das SDK vermeidet es, jedes Mal eine Breaking Change einzuführen, wenn einer Klasse ein Feld hinzugefügt wird.
  </Accordion>

  <Accordion title="Warum verwendet das SDK keine Checked Exceptions?">
    Checked Exceptions gelten weithin als Fehler in der Programmiersprache Java. Tatsächlich wurden sie aus diesem Grund in Kotlin weggelassen.

    Checked Exceptions:

    * Sind umständlich zu behandeln
    * Fördern die Fehlerbehandlung auf der falschen Abstraktionsebene, auf der nichts gegen den Fehler unternommen werden kann
    * Sind aufgrund des Function-Coloring-Problems mühsam weiterzureichen
    * Funktionieren schlecht mit Lambdas (ebenfalls aufgrund des Function-Coloring-Problems)
  </Accordion>
</AccordionGroup>

## Semantische Versionierung

Jede Hauptversion dieses SDK sendet standardmäßig eine API-Version im Header `anthropic-version`, und mit jeder neuen API-Version kommt eine neue Hauptversion. Die erste Hauptversion, die `2026-10-21` sendet, ist 3.0.0; siehe [Migration zur API-Version 2026-10-21](https://platform.claude.com/docs/de/api/migration-2026-10-21#upgrade).

Dieses Paket folgt im Allgemeinen den [SemVer](https://semver.org/spec/v2.0.0.html)-Konventionen, wobei bestimmte abwärtsinkompatible Änderungen als Minor-Versionen veröffentlicht werden können:

1. Änderungen an Bibliotheksinterna, die technisch öffentlich sind, aber nicht für die externe Nutzung vorgesehen oder dokumentiert sind.
2. Änderungen, von denen nicht erwartet wird, dass sie sich in der Praxis auf die überwiegende Mehrheit der Nutzer auswirken.

## Zusätzliche Ressourcen

* [GitHub-Repository](https://github.com/anthropics/anthropic-sdk-java)
* [Javadocs](https://javadoc.io/doc/com.anthropic/anthropic-java)
* [API-Referenz](https://platform.claude.com/docs/de/api/overview)
* [Streaming von Nachrichten](https://platform.claude.com/docs/de/build-with-claude/streaming)
* [Tool-Nutzung mit Claude](https://platform.claude.com/docs/de/agents-and-tools/tool-use/overview)
