java-kotlin
Deep JVM patterns for Java 21+, Kotlin, Spring Boot, JPA, Gradle, JVM tuning, and Android
seniorv1.0.0senior/skills/java-kotlin
View source on GitHubJava / Kotlin
Java 21+ Features
Virtual Threads
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> handleRequest());
}
// Structured Concurrency (preview)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<User> user = scope.fork(() -> fetchUser(id));
Future<Order> order = scope.fork(() -> fetchOrder(id));
scope.join();
scope.throwIfFailed();
return new Response(user.resultNow(), order.resultNow());
}
Pattern Matching
sealed interface Shape permits Circle, Rect {}
record Circle(double radius) implements Shape {}
record Rect(double w, double h) implements Shape {}
double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rect r -> r.w() * r.h();
};
}
Records & Sealed Classes
public record User(Long id, String name, String email) { }
public sealed abstract class Result<T>
permits Success, Failure { }
public record Success<T>(T value) extends Result<T> { }
public record Failure<T>(String error) extends Result<T> { }
Kotlin
Coroutines
suspend fun fetchUser(id: Long): User = withContext(Dispatchers.IO) {
api.getUser(id)
}
fun loadData() {
scope.launch {
val user = async { fetchUser(id) }
val posts = async { fetchPosts(id) }
updateUI(user.await(), posts.await())
}
}
Flow
fun observeData(): Flow<List<Item>> = flow {
while (true) {
emit(repository.getItems())
delay(5000)
}
}.flowOn(Dispatchers.IO)
Sealed Classes
sealed class UiState {
data object Loading : UiState()
data class Success(val data: List<Item>) : UiState()
data class Error(val message: String) : UiState()
}
Spring Boot Patterns
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
private final UserService service;
@GetMapping("/{id}")
public ResponseEntity<User> get(@PathVariable Long id) {
return ResponseEntity.ok(service.findById(id));
}
}
@Service
@Transactional
public class UserService {
private final UserRepository repo;
@Cacheable("users")
public User findById(Long id) {
return repo.findById(id)
.orElseThrow(() -> new NotFoundException("User not found"));
}
}
JPA / Hibernate Optimization
- Use
@BatchSizefor collections. - Prefer
JOIN FETCHover@EntityGraphfor simple cases. - Use
StatelessSessionfor bulk operations. - Configure HikariCP:
maximumPoolSize=10,connectionTimeout=5000. - Enable
hibernate.query.plan_cache_max_sizefor large apps.
Gradle Configuration
plugins {
kotlin("jvm") version "2.0.0"
id("org.springframework.boot") version "3.3.0"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
JVM Tuning
# ZGC (low latency)
-XX:+UseZGC -XX:MaxGCPauseMillis=5 -Xms2g -Xmx2g
# G1GC (throughput)
-XX:+UseG1GC -XX:MaxGCPauseMillis=50 -XX:+ParallelRefProcEnabled
Android (Jetpack Compose)
@Composable
fun UserScreen(viewModel: UserViewModel = hiltViewModel()) {
val state by viewModel.state.collectAsStateWithLifecycle()
when (val s = state) {
is UiState.Loading -> LoadingIndicator()
is UiState.Success -> UserList(s.data)
is UiState.Error -> ErrorMessage(s.message)
}
}
@HiltViewModel
class UserViewModel @Inject constructor(
private val repo: UserRepository
) : ViewModel() {
private val _state = MutableStateFlow<UiState>(UiState.Loading)
val state: StateFlow<UiState> = _state.asStateFlow()
}
- Room: Use
@Transactionfor multi-table writes,Flowfor reactive queries. - Hilt:
@HiltViewModel,@Inject,@Modulefor DI.