mcpField
J
java

java

github.com/claude-dev-suite開発4643 回インストール4 日前に更新
リポジトリ

java について

開発者向けの Java 基礎知識スキルで、モダンな言語機能、コーディングパターン、品質チェック、本番運用の準備を例とともに扱います。静的解析ツール、テスト、エラー処理、性能、トラブルシューティングもまとめています。

主な機能

  1. 01モダン Java 言語機能の例
  2. 02コレクションと Stream のパターン
  3. 03静的解析とスタイルの資料
  4. 04本番運用に向けた実践
  5. 05テストと性能の案内
  6. 06一般的なエラーの診断

活用シーン

  1. 01モダン Java のパターン確認
  2. 02静的解析ルールの選定
  3. 03サービスの本番運用準備
  4. 04Java の一般的な実行時問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill java

インストール後、Claude Code で/javaを入力して読み込まれたか確認します。

詳細

Java コアナレッジ

最新の Java 機能(17 以降)

// Records (immutable data classes)
public record User(Long id, String name, String email) {}

// Sealed classes
public sealed interface Shape permits Circle, Rectangle {}
public final class Circle implements Shape { }
public final class Rectangle implements Shape { }

// Pattern matching for instanceof
if (obj instanceof String s) {
    System.out.println(s.toUpperCase());
}

// Switch expressions
String result = switch (status) {
    case ACTIVE -> "Active";
    case INACTIVE -> "Inactive";
    default -> "Unknown";
};

// Text blocks
String json = """
    {
        "name": "John",
        "age": 30
    }
    """;

コレクションとストリーム

// Stream operations
List<String> names = users.stream()
    .filter(u -> u.isActive())
    .map(User::getName)
    .sorted()
    .collect(Collectors.toList());

// Grouping
Map<Status, List<User>> byStatus = users.stream()
    .collect(Collectors.groupingBy(User::getStatus));

// Optional handling
Optional<User> user = findById(id);
String name = user.map(User::getName).orElse("Unknown");

一般的なパターン

// Builder pattern
User user = User.builder()
    .name("John")
    .email("[email protected]")
    .build();

// Factory method
public static User of(String name, String email) {
    return new User(null, name, email);
}

// Dependency Injection (constructor)
@Service
public class UserService {
    private final UserRepository repository;

    public UserService(UserRepository repository) {
        this.repository = repository;
    }
}

例外処理

// Custom exception
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(Long id) {
        super("User not found: " + id);
    }
}

// Try-with-resources
try (var reader = new BufferedReader(new FileReader(file))) {
    return reader.lines().collect(Collectors.toList());
}

静的解析とリント

公式ルールの参照先
ツールルール数ドキュメント
SonarJava733https://rules.sonarsource.com/java/
Checkstyle200+https://checkstyle.org/checks.html
PMD400+https://pmd.github.io/latest/pmd_rules_java.html
SpotBugs400+https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html
スタイルガイド
ガイドリンク
Google Java Stylehttps://google.github.io/styleguide/javaguide.html
Oracle Code Conventionshttps://www.oracle.com/java/technologies/javase/codeconventions-contents.html
主なルールカテゴリ

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.1</version>
    <configuration>
        <configLocation>google_checks.xml</configLocation>
    </configuration>
</plugin>
有効化すべき重要なルール
カテゴリルールツール
バグNullPointerException のリスクSonarJava S2259
バグリソースリークSonarJava S2095
セキュリティSQL インジェクションSonarJava S3649
セキュリティハードコードされた認証情報SonarJava S2068
保守性認知的複雑度SonarJava S3776
保守性パラメーターが多すぎるCheckstyle

本番環境への対応

エラー処理
// Custom exception hierarchy
public abstract class BaseException extends RuntimeException {
    private final String errorCode;
    private final int httpStatus;

    protected BaseException(String message, String errorCode, int httpStatus) {
        super(message);
        this.errorCode = errorCode;
        this.httpStatus = httpStatus;
    }

    public String getErrorCode() { return errorCode; }
    public int getHttpStatus() { return httpStatus; }
}

public class EntityNotFoundException extends BaseException {
    public EntityNotFoundException(String entity, Object id) {
        super(
            String.format("%s not found with id: %s", entity, id),
            "NOT_FOUND",
            404
        );
    }
}

// Global exception handler
@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(BaseException.class)
    public ResponseEntity<ErrorResponse> handleBaseException(BaseException ex) {
        log.warn("Business error: {}", ex.getMessage());
        return ResponseEntity
            .status(ex.getHttpStatus())
            .body(new ErrorResponse(ex.getErrorCode(), ex.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleUnexpected(Exception ex) {
        log.error("Unexpected error", ex);
        return ResponseEntity
            .status(500)
            .body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
    }
}
Null 安全性
// Use Optional properly
public Optional<User> findById(Long id) {
    return repository.findById(id);
}

// Never return null from Optional
public User getById(Long id) {
    return findById(id)
        .orElseThrow(() -> new EntityNotFoundException("User", id));
}

// Use @Nullable and @NonNull annotations
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

public User updateUser(@NonNull Long id, @Nullable String email) {
    User user = getById(id);
    if (email != null) {
        user.setEmail(email);
    }
    return repository.save(user);
}

// Validation
import jakarta.validation.constraints.*;

public record CreateUserRequest(
    @NotBlank @Size(min = 2, max = 100) String name,
    @NotBlank @Email String email,
    @NotNull @Min(0) Integer age
) {}
ロギング
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

@Service
public class UserService {
    private static final Logger log = LoggerFactory.getLogger(UserService.class);

    public User createUser(CreateUserRequest request) {
        MDC.put("operation", "createUser");
        MDC.put("email", request.email());

        log.info("Creating user");

        try {
            User user = userRepository.save(User.from(request));
            log.info("User created successfully: {}", user.getId());
            return user;
        } catch (Exception e) {
            log.error("Failed to create user", e);
            throw e;
        } finally {
            MDC.clear();
        }
    }
}
テスト
// Unit test with Mockito
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository repository;

    @InjectMocks
    private UserService service;

    @Test
    void shouldCreateUser() {
        // Given
        var request = new CreateUserRequest("John", "[email protected]", 30);
        var expected = new User(1L, "John", "[email protected]", 30);
        when(repository.save(any())).thenReturn(expected);

        // When
        var result = service.createUser(request);

        // Then
        assertThat(result).isEqualTo(expected);
        verify(repository).save(any());
    }

    @Test
    void shouldThrowWhenUserNotFound() {
        // Given
        when(repository.findById(1L)).thenReturn(Optional.empty());

        // When/Then
        assertThatThrownBy(() -> service.getById(1L))
            .isInstanceOf(EntityNotFoundException.class)
            .hasMessageContaining("User not found");
    }
}

// Integration test
@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers
class UserControllerIT {
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldCreateUser() throws Exception {
        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("""
                    {"name": "John", "email": "[email protected]", "age": 30}
                    """))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").exists());
    }
}
パフォーマンス
// Connection pooling (HikariCP)
// application.yml
spring:
  datasource:
    hikari:
      maximum-pool-size: 10
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000

// Caching
@Cacheable(value = "users", key = "#id")
public User findById(Long id) {
    return repository.findById(id).orElseThrow();
}

@CacheEvict(value = "users", key = "#user.id")
public User save(User user) {
    return repository.save(user);
}
監視メトリクス
メトリクス目標
テストカバレッジ> 80%
循環的複雑度< 10
SonarQube のバグ0
セキュリティ脆弱性0
チェックリスト
  • カスタム例外階層
  • グローバル例外ハンドラー
  • DTO に対する Bean Validation
  • null を返す可能性がある場合は Optional を使用
  • @NonNull/@Nullable アノテーション
  • MDC を使用した構造化ロギング
  • Mockito を使用した単体テスト
  • Testcontainers を使用した統合テスト
  • 接続プールの設定
  • 頻繁にアクセスされるデータのキャッシュ

このスキルを使用しない場合

シナリオ代わりに使用
Spring Boot フレームワークbackend-spring-boot スキル
Lombok アノテーションlombok スキル
MapStruct によるマッピングmapstruct スキル
JPA/HibernateORM 固有のスキル
JUnit を使用したテストtesting-junit スキル

アンチパターン

アンチパターン問題点正しい方法
null を返すNullPointerExceptionOptional を使用する
汎用的な Exception をキャッチする個別のエラーが隠れる個別の例外をキャッチする
リソースを閉じないリソースリークtry-with-resources を使用する
変更可能な static フィールドスレッドセーフではない不変または同期化されたものを使用する
ループ内で文字列を連結するO(n²) のパフォーマンスStringBuilder を使用する
空の catch ブロック失敗が表面化しないログを記録するか、例外を再スローする
文字列に == を使用する参照を比較する.equals() を使用する
equals/hashCode をオーバーライドしないコレクションが正しく動作しない両方をオーバーライドするか、どちらもオーバーライドしない

すぐに確認できるトラブルシューティング

問題原因解決策
NullPointerExceptionnull 参照へのアクセスnull を確認し、Optional を使用する
ClassCastException型キャストの誤りキャスト前に instanceof を使用する
ConcurrentModificationException反復処理中の変更Iterator.remove() を使用する
OutOfMemoryErrorヒープの枯渇ヒープを増やし、メモリーリークを修正する
StackOverflowError無限再帰基底条件を追加するか、反復処理を使用する
"Cannot find symbol"コンパイルエラーインポートとスペルを確認する
デッドロックロック依存関係の循環一貫したロック順序を使用する
リソースリークストリームを閉じていないtry-with-resources を使用する

参考ドキュメント

コメント