Java SDK
Installiere und konfiguriere das Anthropic Java SDK mit Builder-Patterns 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.
Installation
implementation("com.anthropic:anthropic-java:2.58.0")Anforderungen
Diese Bibliothek erfordert Java 8 oder höher.
Schnellstart
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 Systemeigenschaften `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)
.build();
Message message = client.messages().create(params);Client-Konfiguration
API-Key-Einrichtung
Konfiguriere den Client über System-Properties oder Umgebungsvariablen:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
// Konfiguriert über die Systemeigenschaften `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:
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:
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();Authentifizierungsoptionen einschließlich Workload Identity Federation findest du unter Authentifizierung. Wenn dein API-Key ein persönlicher Key oder ein Service-Account-Key mit Zugriff auf mehrere Workspaces ist, setze die Workspace-ID im Request-Header anthropic-workspace-id; Einen Workspace auswählen zeigt die Option pro Anfrage für dieses SDK.
Konfigurationsoptionen
| Setter | System-Property | 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" |
System-Properties haben Vorrang vor Umgebungsvariablen.
Konfiguration ändern
Um vorübergehend eine geänderte Client-Konfiguration zu verwenden und dabei dieselben Connection- und Thread-Pools wiederzuverwenden, rufe withOptions() auf einem beliebigen Client oder Service auf:
import com.anthropic.client.AnthropicClient;
AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
optionsBuilder.baseUrl("https://example.com");
optionsBuilder.maxRetries(42);
});Die Methode withOptions() beeinflusst den ursprünglichen Client oder Service nicht.
Asynchrone Nutzung
Der Standard-Client ist synchron. Um zur asynchronen Ausführung zu wechseln, rufe die Methode async() auf:
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)
.build();
CompletableFuture<Message> message = client.async().messages().create(params);Oder erstelle von Anfang an einen asynchronen Client:
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)
.build();
CompletableFuture<Message> message = client.messages().create(params);Der asynchrone Client unterstützt dieselben Optionen wie der synchrone, außer dass die meisten Methoden CompletableFutures 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:
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:
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, pro Client gecachten Thread-Pool-Executor, um zu streamen, ohne den aktuellen Thread zu blockieren. Um einen anderen Executor zu verwenden:
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:
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üge für eine synchrone Antwort einen Stream.peek()-Aufruf zur Stream-Pipeline hinzu, um jedes Event zu akkumulieren:
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üge für eine asynchrone Antwort den MessageAccumulator zum subscribe()-Aufruf hinzu:
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 dieselbe Weise wie der MessageAccumulator verwendet.
Strukturierte Ausgaben
Die vollständige Dokumentation zu strukturierten Ausgaben einschließlich Java-Beispielen findest du unter Strukturierte Ausgaben.
Tool-Nutzung
„Tool use“ (Tool-Nutzung) mit Claude ermöglicht es dir, externe Tools und Funktionen direkt in die Antworten des KI-Modells zu integrieren. Anstatt reinen Text zu erzeugen, kann das Modell bei Bedarf Anweisungen (mit Parametern) zum Aufruf 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 bereitstellst.
Das SDK kann ein Tool und seine Parameter automatisch aus der Struktur einer beliebigen Java-Klasse ableiten: Der Name der Klasse (in Snake-Case konvertiert) liefert den Tool-Namen, und die Felder der Klasse definieren die Parameter des Tools.
Tools mit Annotationen definieren
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 Message-Parametern hinzu und rufe sie dann auf, wenn dies in der Antwort des KI-Modells angefordert wird. BetaToolUseBlock.input(Class<T>) kann verwendet werden, um die Parameter eines Tools in JSON-Form in eine Instanz deiner Tool-definierenden Klasse zu parsen.
Verwende nach dem Aufruf des Tools BetaToolResultBlockParam.Builder.contentAsJson(Object), um das Ergebnis des Tools an das KI-Modell zurückzugeben:
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)
.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.
.addAssistantMessageOfBetaContentBlockParams(
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.
.addUserMessageOfBetaContentBlockParams(
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");
}Konvertierung von Tool-Namen
Tool-Namen werden aus den Camel-Case-Namen der Tool-Klassen (zum Beispiel GetWeather) abgeleitet und in Snake-Case konvertiert (zum Beispiel get_weather). 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 Konvertierung 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:
MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_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 einfachen, in Snake-Case konvertierten Namen der Klasse.@JsonPropertyDescription- Fügt einem Tool-Parameter eine detaillierte Beschreibung hinzu.@JsonIgnore- Schließt einpublic-Feld oder eine Getter-Methode aus dem generierten JSON-Schema für die Parameter eines Tools aus.@JsonProperty- Nimmt ein nicht-public-Feld oder eine Getter-Methode in das generierte JSON-Schema für die Parameter eines Tools auf.
Message Batches
Das SDK bietet Unterstützung für Batch-Verarbeitung unter dem Namespace client.messages().batches(). Unter Paginierung erfährst du, wie du Batches auflistest und durch sie paginierst.
Datei-Uploads
Das SDK definiert Methoden, die Dateien über die Klasse MultipartField akzeptieren:
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:
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 Speicher:
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:
import com.anthropic.core.http.HttpResponse;
HttpResponse response = client.files().download("file_abc123");Um den Antwortinhalt in einer Datei zu speichern:
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:
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 Unchecked-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 Property, 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 für Fehler geworfen, die während des SSE-Streamings nach einer erfolgreichen initialen HTTP-Antwort auftreten.
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
Bei Verwendung von Raw Responses kannst du mit der Methode requestId() auf den Antwort-Header request-id zugreifen:
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();Dies kann verwendet werden, um fehlschlagende Anfragen schnell zu protokollieren und an Anthropic zu melden. Weitere Informationen zum Debuggen von Anfragen findest du unter 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:
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 einen Timeout.
Bei Methoden, die maxTokens akzeptieren, wird der Standard-Timeout jedoch dynamisch mit dieser Formel berechnet, wenn du einen großen maxTokens-Wert angibst und Streaming verwendest:
Duration.ofSeconds(
Math.min(
60 * 60, // 1 hour max
Math.max(
10 * 60, // 10 minute minimum
60 * 60 * maxTokens / 128_000
)
)
)Dies ergibt einen Timeout von bis zu 60 Minuten, skaliert durch den Parameter maxTokens, sofern er nicht überschrieben wird.
Bei Nicht-Streaming-Anfragen skaliert der dynamische Timeout basierend auf maxTokens von einem Minimum von 30 Sekunden bis zu einem Maximum von 10 Minuten.
Um einen benutzerdefinierten Timeout pro Anfrage festzulegen:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());Oder konfiguriere den Standard für alle Methodenaufrufe auf Client-Ebene:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.timeout(Duration.ofSeconds(30))
.build();Lange Anfragen
Vermeide es, einen großen maxTokens-Wert ohne Streaming zu setzen. Manche Netzwerke trennen inaktive Verbindungen nach einer bestimmten Zeit, was dazu führen kann, dass die Anfrage fehlschlägt oder in einen Timeout läuft, ohne eine Antwort von Anthropic zu erhalten. Das SDK pingt die API regelmäßig an, um die Verbindung aufrechtzuerhalten und die Auswirkungen solcher Netzwerke zu verringern.
Das SDK wirft einen Fehler, wenn eine Nicht-Streaming-Anfrage voraussichtlich länger als 10 Minuten dauert. Die Verwendung einer Streaming-Methode oder das Überschreiben des Timeouts auf Client- oder Anfrage-Ebene deaktiviert den Fehler.
Paginierung
Das SDK bietet bequeme Möglichkeiten, auf paginierte Ergebnisse zuzugreifen, entweder seitenweise oder Element für Element über alle Seiten hinweg.
Auto-Paginierung
Um durch alle Ergebnisse über alle Seiten hinweg zu iterieren, verwende die Methode autoPager(), die bei Bedarf automatisch weitere Seiten abruft.
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:
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:
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, um sie zu konstruieren. Jede Klasse ist nach der Konstruktion unveränderlich. Wenn die Klasse einen zugehörigen Builder hat, verfügt sie über eine Methode toBuilder(), mit der sie wieder in einen Builder umgewandelt werden kann, um eine geänderte Kopie zu erstellen.
MessageCreateParams params = MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Claude")
.model(Model.CLAUDE_OPUS_5)
.build();
// Erstelle eine modifizierte Kopie mit toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();Da jede Klasse unveränderlich ist, beeinflussen Änderungen am Builder niemals bereits gebaute Klasseninstanzen.
Anfragen und Antworten
Um eine Anfrage an die Claude API zu senden, baue 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 zu setzen, rufe die Methoden putAdditionalHeader, putAdditionalQueryParam oder putAdditionalBodyProperty auf einer beliebigen Params-Klasse auf:
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 auf dem gebauten Objekt mit den Methoden _additionalHeaders(), _additionalQueryParams() und _additionalBodyProperties() zugegriffen werden.
Um undokumentierte Parameter auf verschachtelten Header-, Query-Parameter- oder Body-Klassen zu setzen:
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 Properties kann später auf dem verschachtelten gebauten Objekt mit der Methode _additionalProperties() zugegriffen werden.
Um einen dokumentierten Parameter oder eine Property auf einen undokumentierten oder noch nicht unterstützten Wert zu setzen, übergib ein JsonValue-Objekt an den entsprechenden Setter:
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)
.build();JsonValue-Erstellung
Der einfachste Weg, ein JsonValue zu erstellen, ist die Verwendung seiner Methode from(...):
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 ein 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 zwangsweise weglassen
Normalerweise wirft die build-Methode einer Builder-Klasse eine IllegalStateException, wenn ein erforderlicher Parameter oder eine erforderliche Property nicht gesetzt ist. Um einen erforderlichen Parameter oder eine Property zwangsweise wegzulassen, übergib JsonMissing:
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)
.maxTokens(JsonMissing.of())
.build();Antwort-Properties
Um auf undokumentierte Antwort-Properties zuzugreifen, rufe die Methode _additionalProperties() auf:
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 ebenfalls überschrieben werden kann
});Um auf den rohen JSON-Wert einer Property zuzugreifen, rufe ihre Methode mit _-Präfix auf:
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 ein literales null gesetzt
} else {
// Prüfe, ob der Wert als String angegeben 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 Property zugreifst.
Um vorab zu prüfen, ob die Antwort vollständig korrekt typisiert ist, rufe validate() auf:
import com.anthropic.models.messages.Message;
Message message = client.messages().create(params).validate();Oder konfiguriere es pro Anfrage:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().responseValidation(true).build());Oder konfiguriere den Standard für alle Methodenaufrufe auf Client-Ebene:
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
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
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, hängt nicht von OkHttp ab. StelltAnthropicClient,AnthropicClientAsyncund deren Implementierungsklassen bereit, die alle mit jedem HTTP-Client funktionieren können.anthropic-java-client-okhttp- Hängt von OkHttp ab. StelltAnthropicOkHttpClientundAnthropicOkHttpClientAsyncbereit.anthropic-java- Hängt vonanthropic-java-coreundanthropic-java-client-okhttpab und stellt deren APIs 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
Um einen angepassten OkHttpClient zu verwenden:
- Ersetze deine
anthropic-java-Abhängigkeit durchanthropic-java-core. - Kopiere die
OkHttpClient-Klasse ausanthropic-java-client-okhttpin deinen Code und passe sie an. - Konstruiere
AnthropicClientImploderAnthropicClientAsyncImplmit deinem angepassten Client.
Vollständig benutzerdefinierter HTTP-Client
Um einen vollständig benutzerdefinierten HTTP-Client zu verwenden:
- Ersetze deine
anthropic-java-Abhängigkeit durchanthropic-java-core. - Schreibe eine Klasse, die das Interface
HttpClientimplementiert. - Konstruiere
AnthropicClientImploderAnthropicClientAsyncImplmit deiner neuen Client-Klasse.
Plattformintegrationen
Das Java SDK unterstützt die folgenden Plattformen über separate Abhängigkeiten, die plattformspezifische Backend-Implementierungen bereitstellen:
- Agent Platform:
com.anthropic:anthropic-java-vertex: VerwendeVertexBackend.fromEnv()oderVertexBackend.builder(). - Bedrock:
com.anthropic:anthropic-java-bedrock: VerwendeBedrockMantleBackend.fromEnv()oderBedrockMantleBackend.builder()für den Messages-API-Bedrock-Endpunkt, oderBedrockBackend.fromEnv()/BedrockBackend.builder()(bedrock-runtime-Pfad). - Claude Platform on AWS:
com.anthropic:anthropic-java-aws: VerwendeAwsBackend.fromEnv()(liestANTHROPIC_AWS_WORKSPACE_IDund die AWS-Standard-Region/Credential-Chain) oderAwsBackend.builder(). In der Beta verfügbar. - Foundry:
com.anthropic:anthropic-java-foundry: VerwendeFoundryBackend.fromEnv()oderFoundryBackend.builder().
Verwende BedrockMantleBackend für neue Projekte; BedrockBackend bleibt für bestehende Anwendungen erhalten, die die Bedrock-InvokeModel-API verwenden.
Jede Backend-Implementierung wird dem Client mit .backend() auf AnthropicOkHttpClient.builder() übergeben. Jedes Cloud-Backend bindet die Klassen des jeweiligen Cloud-Plattform-SDK als transitive Abhängigkeiten ein.
Erweiterte Nutzung
Zugriff auf Raw Responses
Um auf HTTP-Header, Statuscodes und den rohen Antwort-Body zuzugreifen, stelle jedem HTTP-Methodenaufruf withRawResponse() voran:
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)
.build();
HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);
int statusCode = message.statusCode();
Headers headers = message.headers();Du kannst die Antwort bei Bedarf weiterhin in eine Instanz einer Java-Klasse deserialisieren:
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:
export ANTHROPIC_LOG=infoOder auf debug für ausführlicheres Logging:
export ANTHROPIC_LOG=debugDas 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.
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 für diese Fälle aktualisieren.
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.
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 zu setzen, verwende die Methoden putAdditionalHeader, putAdditionalQueryParam oder putAdditionalBodyProperty, wie unter Undokumentierte Parameter beschrieben.
Undokumentierte Antwort-Properties
Um auf undokumentierte Antwort-Properties zuzugreifen, verwende die Methode _additionalProperties(), wie unter Antwort-Properties beschrieben.
Neue oder unveröffentlichte Enum-Werte
Enum-ähnliche Klassen im SDK, wie Model und AnthropicBeta, sind keine geschlossenen Java-enum-Typen. Jede von ihnen 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:
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:
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. Du kannst die Verfügbarkeit aller Fähigkeiten und Tools von Claude in der Übersicht „Mit Claude entwickeln“ 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 Bauen der Message-Parameter den entsprechenden Beta-Header mit .addBeta() hinzu.
Zum Beispiel, um Context Editing zu aktivieren:
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)
.maxTokens(1024L)
.addBeta(AnthropicBeta.CONTEXT_MANAGEMENT_2025_06_27)
.addUserMessage("Hello, Claude")
.build());
}Häufig gestellte Fragen
Java-enum-Klassen sind nicht ohne Weiteres vorwärtskompatibel. Ihre Verwendung im SDK könnte Laufzeit-Exceptions verursachen, wenn die API aktualisiert wird und mit einem neuen Enum-Wert antwortet.
Da diese Klassen offen sind, kannst du sie über ihre Factory-Methode of(String) auch mit einem beliebigen String-Wert konstruieren. Siehe Neue oder unveröffentlichte Enum-Werte, wenn du einen Wert verwenden musst, der in deiner SDK-Version noch nicht enthalten ist.
Die Verwendung von JsonField<T> ermöglicht einige Funktionen:
- Nutzung undokumentierter API-Funktionalität
- Verzögerte Validierung der API-Antwort gegen die erwartete Form
- Darstellung von fehlenden gegenüber explizit null gesetzten Werten
Das Hinzufügen neuer Felder zu einer Data-Klasse ist nicht rückwärtskompatibel, und das SDK vermeidet es, jedes Mal einen Breaking Change einzuführen, wenn einer Klasse ein Feld hinzugefügt wird.
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 Fehlerbehandlung auf der falschen Abstraktionsebene, wo nichts gegen den Fehler unternommen werden kann
- Sind wegen des Function-Coloring-Problems mühsam weiterzureichen
- Funktionieren nicht gut mit Lambdas (ebenfalls wegen des Function-Coloring-Problems)
Semantische Versionierung
Dieses Paket folgt im Allgemeinen den SemVer-Konventionen, wobei bestimmte rückwärtsinkompatible Änderungen als Minor-Versionen veröffentlicht werden können:
- Änderungen an Bibliotheksinterna, die technisch öffentlich sind, aber nicht für die externe Nutzung vorgesehen oder dokumentiert sind.
- Änderungen, von denen nicht erwartet wird, dass sie die überwiegende Mehrheit der Nutzer in der Praxis betreffen.
Zusätzliche Ressourcen
Was this page helpful?