Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Claude SDK for Java
https://github.com/anthropics/anthropic-sdk-java
Admin
Claude SDK for Java provides access to the Claude API from Java applications, enabling developers to
...
Tokens:
8,805
Snippets:
48
Trust Score:
8.8
Update:
6 days ago
Context
Skills
Chat
Benchmark
85.7
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Claude SDK for Java The Claude SDK for Java provides a comprehensive, type-safe interface for interacting with Anthropic's Claude API from Java and Kotlin applications. Built with modern Java practices, the SDK supports both synchronous and asynchronous operations, streaming responses, tool/function calling, structured outputs, extended thinking, and integration with cloud backends including Amazon Bedrock and Google Cloud Vertex AI. The SDK is designed for production use with built-in connection pooling, automatic retries with exponential backoff, rate limiting, and proper resource management. It requires Java 8+ and uses OkHttp as the underlying HTTP client. The SDK handles JSON serialization/deserialization via Jackson and provides immutable request/response objects with builder patterns for constructing API calls. ## Creating a Client The AnthropicClient is the main entry point for all API interactions. Create a single instance and reuse it across your application as it manages connection pools and thread pools internally. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; // Create client from environment variable ANTHROPIC_API_KEY AnthropicClient client = AnthropicOkHttpClient.fromEnv(); // Or configure explicitly with API key AnthropicClient client = AnthropicOkHttpClient.builder() .apiKey("sk-ant-...") .build(); // Close the client when done (optional - resources auto-release when idle) client.close(); ``` ## Sending Messages (Synchronous) The Messages API allows you to send conversations to Claude and receive complete responses. Use MessageCreateParams to configure the model, max tokens, and message content. ```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() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Tell me a story about building the best SDK!") .build(); Message message = client.messages().create(params); // Extract text content from response message.content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); // Access usage information System.out.println("Input tokens: " + message.usage().inputTokens()); System.out.println("Output tokens: " + message.usage().outputTokens()); ``` ## Sending Messages (Asynchronous) For non-blocking operations, use AnthropicClientAsync which returns CompletableFuture for all API calls. ```java import com.anthropic.client.AnthropicClientAsync; import com.anthropic.client.okhttp.AnthropicOkHttpClientAsync; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; AnthropicClientAsync client = AnthropicOkHttpClientAsync.fromEnv(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Tell me a story about building the best SDK!") .build(); client.messages() .create(params) .thenAccept(message -> message.content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text()))) .join(); ``` ## Streaming Responses (Synchronous) Streaming allows you to receive partial responses as they're generated, providing better user experience for long responses. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.core.http.StreamResponse; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; import com.anthropic.models.messages.RawMessageStreamEvent; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Tell me a story about building the best SDK!") .build(); // Use try-with-resources to ensure proper cleanup try (StreamResponse<RawMessageStreamEvent> stream = client.messages().createStreaming(params)) { stream.stream() .flatMap(event -> event.contentBlockDelta().stream()) .flatMap(delta -> delta.delta().text().stream()) .forEach(textDelta -> System.out.print(textDelta.text())); } ``` ## Streaming Responses (Asynchronous) Async streaming uses a subscription-based model for handling events. ```java import com.anthropic.client.AnthropicClientAsync; import com.anthropic.client.okhttp.AnthropicOkHttpClientAsync; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; AnthropicClientAsync client = AnthropicOkHttpClientAsync.fromEnv(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Tell me a story about building the best SDK!") .build(); client.messages() .createStreaming(params) .subscribe(event -> event.contentBlockDelta().stream() .flatMap(delta -> delta.delta().text().stream()) .forEach(textDelta -> System.out.print(textDelta.text()))) .onCompleteFuture() .join(); ``` ## Multi-Turn Conversations Build conversations by appending messages to a params builder. The SDK supports adding assistant responses back to maintain conversation context. ```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(); // Use a builder to accumulate conversation history MessageCreateParams.Builder paramsBuilder = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Tell me a story about building the best SDK!"); for (int i = 0; i < 4; i++) { Message response = client.messages().create(paramsBuilder.build()); response.content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); System.out.println("\n-----------------------------------\n"); // Add assistant response and follow-up user message paramsBuilder.addMessage(response).addUserMessage("But why?" + "?".repeat(i)); } ``` ## Tool Use / Function Calling Define tools using Jackson-annotated Java classes. Claude can invoke these tools, and you handle execution and return results. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.beta.messages.*; import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import java.util.List; @JsonClassDescription("Get the weather in a given location") class GetWeather { @JsonPropertyDescription("The city and state, e.g. San Francisco, CA") public String location; @JsonPropertyDescription("The unit of temperature") public String unit; public String execute() { // Implement actual weather lookup return "{\"temperature\": \"72°F\", \"conditions\": \"sunny\"}"; } } AnthropicClient client = AnthropicOkHttpClient.fromEnv(); MessageCreateParams.Builder paramsBuilder = MessageCreateParams.builder() .model("claude-sonnet-4-5") .putAdditionalHeader("anthropic-beta", "structured-outputs-2025-11-13") .maxTokens(2048) .addTool(GetWeather.class) .addUserMessage("What's the temperature in New York?"); // First call - Claude requests tool use BetaMessage response = client.beta().messages().create(paramsBuilder.build()); response.content().stream() .flatMap(block -> block.toolUse().stream()) .forEach(toolUse -> { // Add tool use request to conversation paramsBuilder.addAssistantMessageOfBetaContentBlockParams( List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder() .name(toolUse.name()) .id(toolUse.id()) .input(toolUse._input()) .build()))); // Execute tool and add result GetWeather tool = toolUse.input(GetWeather.class); String result = tool != null ? tool.execute() : "{}"; paramsBuilder.addUserMessageOfBetaContentBlockParams( List.of(BetaContentBlockParam.ofToolResult(BetaToolResultBlockParam.builder() .toolUseId(toolUse.id()) .content(result) .build()))); }); // Second call - Claude responds with tool results BetaMessage finalResponse = client.beta().messages().create(paramsBuilder.build()); finalResponse.content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); ``` ## Tool Runner (Automatic Tool Execution) The BetaToolRunner automatically handles tool execution loops, simplifying agentic workflows. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.helpers.BetaToolRunner; import com.anthropic.models.beta.messages.BetaMessage; import com.anthropic.models.beta.messages.MessageCreateParams; import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import java.util.function.Supplier; @JsonClassDescription("Get the weather in a given location") class GetWeather implements Supplier<String> { @JsonPropertyDescription("The city and state, e.g. San Francisco, CA") public String location; @Override public String get() { return "The weather in " + location + " is foggy and 60°F"; } } AnthropicClient client = AnthropicOkHttpClient.fromEnv(); BetaToolRunner toolRunner = client.beta() .messages() .toolRunner(MessageCreateParams.builder() .model("claude-sonnet-4-5") .putAdditionalHeader("anthropic-beta", "structured-outputs-2025-11-13") .maxTokens(1000) .addUserMessage("What is the weather in San Francisco?") .addTool(GetWeather.class) .build()); // Iterate through all messages in the tool execution loop for (BetaMessage message : toolRunner) { System.out.println(message); } ``` ## Extended Thinking Enable Claude's extended thinking capability to show its reasoning process before providing a final answer. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.ContentBlock; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; import com.anthropic.models.messages.ThinkingConfigEnabled; import java.util.List; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .thinking(ThinkingConfigEnabled.builder().budgetTokens(1024).build()) .addUserMessage("What is the solution to the equation x^2 + 5x + 6 = 0?") .build(); List<ContentBlock> blocks = client.messages().create(params).content(); for (ContentBlock block : blocks) { if (block.isThinking()) { System.out.println("Thinking: " + block.asThinking().thinking()); } else if (block.isText()) { System.out.println("Answer: " + block.asText().text()); } } ``` ## Structured Outputs Get type-safe JSON responses by specifying an output class. The SDK validates responses against your Java class structure. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; import com.anthropic.models.messages.StructuredMessageCreateParams; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import java.util.List; class Person { @JsonPropertyDescription("The first name and surname of the person.") public String name; public int birthYear; @JsonPropertyDescription("The year the person died, or 'present' if living.") public String deathYear; } class Book { public String title; public Person author; @JsonPropertyDescription("The year the book was first published.") public int publicationYear; public String genre; } class BookList { public List<Book> books; } AnthropicClient client = AnthropicOkHttpClient.fromEnv(); StructuredMessageCreateParams<BookList> params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_5_20250929) .maxTokens(2048) .outputConfig(BookList.class) .addUserMessage("List some famous late twentieth century novels.") .build(); client.messages().create(params).content().stream() .flatMap(block -> block.text().stream()) .flatMap(textBlock -> textBlock.text().books.stream()) .forEach(book -> System.out.println(" - " + book.title + " by " + book.author.name)); ``` ## Image Input Send images to Claude for analysis using base64-encoded data or URLs. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.*; import java.io.IOException; import java.util.Base64; import java.util.List; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); // Load and encode image byte[] imageBytes = Files.readAllBytes(Path.of("image.png")); String imageBase64 = Base64.getEncoder().encodeToString(imageBytes); ContentBlockParam imageParam = ContentBlockParam.ofImage(ImageBlockParam.builder() .source(Base64ImageSource.builder() .mediaType(Base64ImageSource.MediaType.IMAGE_PNG) .data(imageBase64) .build()) .build()); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Describe this image.") .addUserMessageOfBlockParams(List.of(imageParam)) .build(); client.messages().create(params).content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); ``` ## Message Batches Process multiple messages asynchronously using the batch API for high-throughput workloads. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.core.http.StreamResponse; import com.anthropic.models.messages.Model; import com.anthropic.models.messages.batches.*; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); BatchCreateParams params = BatchCreateParams.builder() .addRequest(BatchCreateParams.Request.builder() .customId("request-1") .params(BatchCreateParams.Request.Params.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("What is the capital of France?") .build()) .build()) .addRequest(BatchCreateParams.Request.builder() .customId("request-2") .params(BatchCreateParams.Request.Params.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("What is the capital of Japan?") .build()) .build()) .build(); // Create batch MessageBatch batch = client.messages().batches().create(params); // Poll for completion while (batch.processingStatus().equals(MessageBatch.ProcessingStatus.IN_PROGRESS)) { Thread.sleep(2000); batch = client.messages().batches().retrieve( BatchRetrieveParams.builder().messageBatchId(batch.id()).build()); } // Stream results try (StreamResponse<MessageBatchIndividualResponse> results = client.messages() .batches().resultsStreaming(BatchResultsParams.builder() .messageBatchId(batch.id()).build())) { results.stream().forEach(response -> { System.out.println(response.customId() + ": "); response.result().asSucceeded().message().content().stream() .flatMap(block -> block.text().stream()) .forEach(text -> System.out.println(text.text())); }); } // Delete batch when done client.messages().batches().delete( BatchDeleteParams.builder().messageBatchId(batch.id()).build()); ``` ## Token Counting Count tokens before sending requests to estimate costs and manage context windows. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.MessageCountTokensParams; import com.anthropic.models.messages.Model; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); MessageCountTokensParams params = MessageCountTokensParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .addUserMessage("Tell me a story about building the best SDK!") .build(); long inputTokens = client.messages().countTokens(params).inputTokens(); System.out.println("Input tokens: " + inputTokens); ``` ## List Available Models Retrieve all available Claude models using the models endpoint with automatic pagination. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); // Auto-paginate through all available models client.models().list().autoPager().forEach(model -> { System.out.println("Model ID: " + model.id()); System.out.println("Display Name: " + model.displayName()); }); ``` ## Amazon Bedrock Backend Use Claude models hosted on Amazon Bedrock by configuring the BedrockBackend. ```java import com.anthropic.bedrock.backends.BedrockBackend; import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.MessageCreateParams; // Configure from environment variables AWS_REGION and AWS_BEARER_TOKEN_BEDROCK AnthropicClient client = AnthropicOkHttpClient.builder() .backend(BedrockBackend.builder().fromEnv().build()) .build(); // Or configure explicitly AnthropicClient client = AnthropicOkHttpClient.builder() .backend(BedrockBackend.builder() .region("us-east-1") .apiKey("your-api-key") .build()) .build(); MessageCreateParams params = MessageCreateParams.builder() .model("us.anthropic.claude-opus-4-20250514-v1:0") .maxTokens(2048) .addUserMessage("Hello from Bedrock!") .build(); client.messages().create(params).content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); ``` ## Google Cloud Vertex AI Backend Use Claude models hosted on Google Cloud Vertex AI. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.vertex.backends.VertexBackend; import com.google.auth.oauth2.GoogleCredentials; GoogleCredentials credentials = GoogleCredentials.getApplicationDefault(); AnthropicClient client = AnthropicOkHttpClient.builder() .backend(VertexBackend.builder() .googleCredentials(credentials) .region("us-central1") .project("your-project-id") .build()) .build(); MessageCreateParams params = MessageCreateParams.builder() .model("claude-sonnet-4@20250514") .maxTokens(2048) .addUserMessage("Hello from Vertex AI!") .build(); client.messages().create(params).content().stream() .flatMap(block -> block.text().stream()) .forEach(textBlock -> System.out.println(textBlock.text())); ``` ## MCP (Model Context Protocol) Integration Connect Claude to MCP servers for extended capabilities. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.core.http.StreamResponse; import com.anthropic.models.beta.messages.*; import com.anthropic.models.messages.Model; import java.util.Arrays; import java.util.List; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); BetaRequestMcpServerToolConfiguration toolConfig = BetaRequestMcpServerToolConfiguration.builder() .enabled(true) .allowedTools(Arrays.asList("echo", "add")) .build(); BetaRequestMcpServerUrlDefinition mcpServer = BetaRequestMcpServerUrlDefinition.builder() .url("http://example-server.modelcontextprotocol.io/sse") .name("example") .toolConfiguration(toolConfig) .build(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(1000) .mcpServers(List.of(mcpServer)) .addUserMessage("Calculate 1+2") .putAdditionalHeader("anthropic-beta", "mcp-client-2025-04-04") .build(); try (StreamResponse<BetaRawMessageStreamEvent> stream = client.beta().messages().createStreaming(params)) { stream.stream() .flatMap(event -> event.contentBlockDelta().stream()) .flatMap(delta -> delta.delta().text().stream()) .forEach(textDelta -> System.out.print(textDelta.text())); } ``` ## Client Configuration Options Configure timeouts, retries, headers, and other client options. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.core.Timeout; import java.time.Duration; AnthropicClient client = AnthropicOkHttpClient.builder() .apiKey("sk-ant-...") .baseUrl("https://api.anthropic.com") // Set request timeout .timeout(Duration.ofMinutes(5)) // Or configure granular timeouts .timeout(Timeout.builder() .connect(Duration.ofSeconds(30)) .read(Duration.ofMinutes(5)) .write(Duration.ofMinutes(1)) .request(Duration.ofMinutes(10)) .build()) // Configure retry behavior (default: 2 retries) .maxRetries(3) // Add custom headers .putHeader("X-Custom-Header", "value") // Enable response validation .responseValidation(true) // Configure connection pooling .maxIdleConnections(10) .keepAliveDuration(Duration.ofMinutes(5)) .build(); ``` ## Error Handling Handle API errors with specific exception types for different error conditions. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.errors.*; import com.anthropic.models.messages.MessageCreateParams; import com.anthropic.models.messages.Model; AnthropicClient client = AnthropicOkHttpClient.fromEnv(); try { MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Hello!") .build(); client.messages().create(params); } catch (BadRequestException e) { // 400 - Invalid request parameters System.err.println("Bad request: " + e.getMessage()); } catch (UnauthorizedException e) { // 401 - Invalid API key System.err.println("Unauthorized: " + e.getMessage()); } catch (PermissionDeniedException e) { // 403 - Permission denied System.err.println("Permission denied: " + e.getMessage()); } catch (NotFoundException e) { // 404 - Resource not found System.err.println("Not found: " + e.getMessage()); } catch (RateLimitException e) { // 429 - Rate limit exceeded System.err.println("Rate limited: " + e.getMessage()); } catch (InternalServerException e) { // 5xx - Server error System.err.println("Server error: " + e.getMessage()); } catch (AnthropicServiceException e) { // Other service errors System.err.println("Status: " + e.statusCode()); System.err.println("Headers: " + e.headers()); System.err.println("Body: " + e.body()); } ``` ## Raw HTTP Response Access Access raw HTTP responses including headers and status codes for advanced use cases. ```java import com.anthropic.client.AnthropicClient; import com.anthropic.client.okhttp.AnthropicOkHttpClient; import com.anthropic.core.http.HttpResponseFor; 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() .model(Model.CLAUDE_SONNET_4_20250514) .maxTokens(2048) .addUserMessage("Hello!") .build(); HttpResponseFor<Message> response = client.withRawResponse() .messages() .create(params); System.out.println("Status: " + response.statusCode()); System.out.println("Request ID: " + response.headers().get("x-request-id")); Message message = response.body(); ``` ## Summary The Claude SDK for Java is designed for building production-grade AI applications that leverage Claude's capabilities. Common use cases include building conversational chatbots with multi-turn context management, integrating AI-powered features into existing Java applications, creating agentic workflows with tool execution loops, processing documents and images with multimodal inputs, and generating structured data outputs for downstream processing. The SDK follows Java best practices with immutable objects, builder patterns, and proper resource management. For integration, create a single client instance per application, use the async client for non-blocking operations in reactive systems, implement proper error handling with specific exception types, and leverage streaming for responsive user experiences. The SDK's support for Amazon Bedrock and Google Cloud Vertex AI backends makes it suitable for enterprise deployments with existing cloud infrastructure.