Modern Java - Java 8'dan keyingi muhim yangiliklar. Middle developer faqat Java 8 Stream bilan qolib ketmasligi kerak. Hozir real loyihalarda Java 11, 17 va 21 ko‘p ishlatiladi.
Bu bo‘limga quyidagilar kiradi: Records, Sealed classes, Pattern matching, Text blocks, var, Virtual threads.
1. Java 11-21 nima uchun muhim?
Java 8 uzoq vaqt standart bo‘lib keldi. Lekin Java 11, 17, 21 versiyalarida kodni:
kamroq boilerplate
o‘qilishi oson
type-safe
immutabilityga yaqin
concurrency uchun qulay
productionga mosqilish uchun ko‘p imkoniyatlar qo‘shildi.
Backend developer uchun eng muhimlari:
Feature | Qayerda kerak |
|---|---|
| Local variablelarda qisqa yozish |
Text Blocks | SQL, JSON, HTML yozish |
Records | DTO, response, immutable data object |
Pattern Matching |
|
Sealed Classes | Cheklangan inheritance |
Virtual Threads | Ko‘p blocking I/O requestlar |
2. var - Local Type Inference
var Java 10'da kelgan. U local variable type’ni compilerga aniqlatadi.
Oldin:
String name = "Ali";
List<String> users = new ArrayList<>();var bilan:
var name = "Ali";
var users = new ArrayList<String>();Compiler o‘zi tushunadi:
name -> String
users -> ArrayList<String>var qayerda yaxshi?
Agar type aniq ko‘rinib tursa:
var user = new User("Ali", "ali@example.com");
var amount = BigDecimal.valueOf(100_000);
var formatter = DateTimeFormatter.ISO_LOCAL_DATE;Bu yaxshi, chunki o‘qishda muammo yo‘q.
var qayerda yomon?
Agar method nomidan type bilinmasa:
var result = service.process(data);
var value = manager.get();
var response = client.call();Bu joyda var o‘qishni qiyinlashtiradi. Developer result nimani anglatishini IDE’siz bilmaydi.
Yaxshiroq:
PaymentResponse response = paymentClient.createPayment(request);var fieldlarda ishlaydimi?
Yo‘q.
private var name = "Ali"; // xatovar faqat local variable uchun ishlaydi:
public void test() {
var name = "Ali";
}var bilan null
Bu ishlamaydi:
var user = null; // compiler type’ni bilmaydiTo‘g‘ri:
User user = null;3. Text Blocks
Text Blocks Java 15'da stable bo‘lgan. Ko‘p qatorli stringlarni qulay yozish uchun.
Oldin SQL yozish noqulay edi:
String sql = "SELECT * " +
"FROM users " +
"WHERE status = 'ACTIVE'";Text block bilan:
String sql = """
SELECT *
FROM users
WHERE status = 'ACTIVE'
""";Ancha o‘qilishi oson.
JSON uchun
Oldin:
String json = "{ \"name\": \"Ali\", \"age\": 25 }";Text block bilan:
String json = """
{
"name": "Ali",
"age": 25
}
""";Testlarda juda foydali:
mockMvc.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"name": "Ali",
"email": "ali@example.com"
}
"""))
.andExpect(status().isOk());JPQL yoki native query uchun
@Query("""
select u
from User u
where u.status = :status
order by u.createdAt desc
""")
List<User> findByStatus(UserStatus status);Bu + bilan string ulashdan ancha toza.
4. Records
Record - data tashish uchun qisqa, immutable’ga yaqin class.
Oddiy DTO yozsak:
public class UserDto {
private final Long id;
private final String name;
private final String email;
public UserDto(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}Record bilan:
public record UserDto(
Long id,
String name,
String email
) {
}Java avtomatik yaratadi:
constructor
accessor methods
equals()
hashCode()
toString()Record accessor methodlari
Record’da getter nomi boshqacha:
UserDto dto = new UserDto(1L, "Ali", "ali@example.com");
System.out.println(dto.id());
System.out.println(dto.name());
System.out.println(dto.email());getId() emas, id().
Record qayerda yaxshi?
Record quyidagilar uchun juda qulay:
DTO
API response
API request
projection
event object
command object
test data
small immutable value objectMasalan:
public record CreateUserRequest(
String name,
String email,
String phone
) {
}public record OrderCreatedEvent(
Long orderId,
Long userId
) {
}public record UserListItemDto(
Long id,
String fullName
) {
}Record validation bilan
public record RegisterRequest(
@NotBlank String name,
@Email String email,
@Pattern(regexp = "^\\+998\\d{9}$") String phone
) {
}Controller:
@PostMapping("/register")
public ResponseEntity<UserDto> register(@Valid @RequestBody RegisterRequest request) {
return ResponseEntity.ok(userService.register(request));
}Record ichida custom constructor
Agar qoida qo‘shmoqchi bo‘lsang:
public record Money(BigDecimal amount, String currency) {
public Money {
if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Amount manfiy bo‘lmasin");
}
if (currency == null || currency.isBlank()) {
throw new IllegalArgumentException("Currency bo‘sh bo‘lmasin");
}
}
}Bu compact constructor deyiladi.
Record entity bo‘la oladimi?
Texnik tomondan record immutable. JPA/Hibernate entity uchun no-args constructor, proxy, mutable state kerak bo‘lishi mumkin. Shuning uchun odatda:
Record -> DTO uchun yaxshi
Class -> Entity uchun yaxshiYomon:
@Entity
public record User(Long id, String name) {
}Yaxshi:
@Entity
public class User {
// entity
}
public record UserDto(Long id, String name) {
// DTO
}5. Pattern Matching for instanceof
Oldin:
if (obj instanceof String) {
String text = (String) obj;
System.out.println(text.toUpperCase());
}Yangi usul:
if (obj instanceof String text) {
System.out.println(text.toUpperCase());
}Bu yerda Java o‘zi cast qiladi.
Real misol
public String formatValue(Object value) {
if (value instanceof String text) {
return text.trim().toUpperCase();
}
if (value instanceof Integer number) {
return "Number: " + number;
}
if (value instanceof BigDecimal amount) {
return "Amount: " + amount;
}
return "Unknown";
}Kod qisqaroq va xavfsizroq.
6. Pattern Matching for switch
Java 21'da pattern matching for switch stable bo‘ldi.
Oldingi usul:
public String describe(Object obj) {
if (obj instanceof String s) {
return "String: " + s;
} else if (obj instanceof Integer i) {
return "Integer: " + i;
} else if (obj instanceof Long l) {
return "Long: " + l;
}
return "Unknown";
}Yangi usul:
public String describe(Object obj) {
return switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Integer: " + i;
case Long l -> "Long: " + l;
case null -> "Null";
default -> "Unknown";
};
}Bu ayniqsa sealed classlar bilan kuchli ishlaydi.
7. Switch Expression
Java 14'da switch expression stable bo‘lgan.
Oldin:
String result;
switch (status) {
case NEW:
result = "Yangi";
break;
case PAID:
result = "To‘langan";
break;
default:
result = "Noma’lum";
}Yangi usul:
String result = switch (status) {
case NEW -> "Yangi";
case PAID -> "To‘langan";
case CANCELLED -> "Bekor qilingan";
};Agar enum barcha qiymatlar qamrab olingan bo‘lsa, default shart bo‘lmasligi mumkin.
Real misol
public BigDecimal calculateFee(PaymentType type, BigDecimal amount) {
return switch (type) {
case PAYME -> amount.multiply(BigDecimal.valueOf(0.01));
case CLICK -> amount.multiply(BigDecimal.valueOf(0.012));
case CASH -> BigDecimal.ZERO;
};
}Bu if/elsedan o‘qilishi yaxshi.
8. Sealed Classes
Sealed class/interface - qaysi classlar extend/implement qila olishini cheklaydi.
Masalan, payment result faqat 3 xil bo‘lishi mumkin:
Success
Failed
PendingSealed interface:
public sealed interface PaymentResult
permits PaymentSuccess, PaymentFailed, PaymentPending {
}Implementationlar:
public record PaymentSuccess(String transactionId)
implements PaymentResult {
}public record PaymentFailed(String reason)
implements PaymentResult {
}public record PaymentPending(String message)
implements PaymentResult {
}Endi boshqa class PaymentResultni implement qila olmaydi, agar permits ichida bo‘lmasa.
Sealed + switch
public String handle(PaymentResult result) {
return switch (result) {
case PaymentSuccess success -> "Success: " + success.transactionId();
case PaymentFailed failed -> "Failed: " + failed.reason();
case PaymentPending pending -> "Pending: " + pending.message();
};
}Bu yerda compiler hamma holat qamrab olinganini tekshiradi.
Agar keyin yangi type qo‘shsak:
public record PaymentExpired(String message) implements PaymentResult {
}switch sizni ogohlantiradi: yangi case qo‘shish kerak.
Sealed qachon kerak?
Quyidagi holatlarda:
natija turlari cheklangan bo‘lsa
domain state aniq bo‘lsa
command/event turlari nazorat qilinsa
error model aniq bo‘lsa
compiler yordamida exhaustive checking kerak bo‘lsaMasalan:
public sealed interface OrderState
permits NewOrder, PaidOrder, CancelledOrder, DeliveredOrder {
}Yoki:
public sealed interface ApiResult
permits SuccessResult, ValidationErrorResult, ServerErrorResult {
}9. Helpful NullPointerException
Java 14'dan boshlab NPE xabarlari ancha tushunarli bo‘ldi.
Oldin:
NullPointerExceptionYangi xabarlar aniqroq:
Cannot invoke "User.getName()" because "user" is nullMasalan:
Order order = null;
System.out.println(order.getUser().getName());Xato qaysi object null ekanini ko‘rsatadi.
Bu debuggingda juda foydali.
10. Optional yaxshiroq ishlatish
Optional Java 8'da kelgan, lekin modern Java’da ham to‘g‘ri ishlatish muhim.
Yomon:
Optional<User> optional = userRepository.findById(id);
if (optional.isPresent()) {
return optional.get();
}
throw new RuntimeException("User topilmadi");Yaxshi:
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User topilmadi"));Optional field sifatida ishlatilmasin
Yomon:
public class User {
private Optional<String> phone;
}Yaxshi:
public class User {
private String phone;
}Optional asosan method return type uchun ishlatiladi.
11. Collection factory methods
Java 9'dan boshlab immutable collection yaratish osonlashdi.
Oldin:
List<String> roles = Arrays.asList("ADMIN", "USER");Yangi:
List<String> roles = List.of("ADMIN", "USER");
Set<String> permissions = Set.of("READ", "WRITE");
Map<String, Integer> limits = Map.of(
"daily", 100,
"monthly", 1000
);Bu collectionlar immutable:
roles.add("MANAGER"); // UnsupportedOperationExceptionQayerda yaxshi?
private static final List<String> PUBLIC_URLS = List.of(
"/api/auth/login",
"/api/auth/register",
"/actuator/health"
);Yoki test data:
var items = List.of(
new OrderItem("Laptop", 1),
new OrderItem("Mouse", 2)
);12. Stream API yangiliklari
Java 16'dan toList() qo‘shildi.
Oldin:
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());Yangi:
List<String> names = users.stream()
.map(User::getName)
.toList();Lekin farq bor: stream().toList() qaytargan list unmodifiable bo‘lishi mumkin.
names.add("Vali"); // UnsupportedOperationException bo‘lishi mumkinAgar mutable list kerak bo‘lsa:
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(ArrayList::new));13. String API yangiliklari
Java 11'da foydali methodlar bor:
" ".isBlank(); // true
" Ali ".strip(); // "Ali"
"Java\nSpring".lines(); // Stream<String>
"ha".repeat(3); // "hahaha"Misol:
public boolean isValidName(String name) {
return name != null && !name.isBlank();
}isBlank() trim().isEmpty()dan qulayroq.
14. HttpClient
Java 11'da built-in HTTP client bor.
Oldin ko‘pincha Apache HttpClient yoki OkHttp ishlatilardi. Hozir oddiy holatlar uchun Java’ning o‘zidagi HttpClient ham yetarli.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
System.out.println(response.body());Async:
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);Spring loyihalarda esa ko‘pincha:
RestClient
WebClient
Feignishlatiladi. Lekin Java HttpClientni bilish foydali.
15. Virtual Threads
Virtual threads Java 21'da eng muhim yangiliklardan biri.
Oddiy platform thread OS thread bilan bog‘langan:
Java Thread -> OS ThreadVirtual thread esa ancha yengil:
Ko‘p virtual thread -> kamroq platform threadlarda boshqariladiOddiy thread pool
ExecutorService executor = Executors.newFixedThreadPool(100);
executor.submit(() -> {
processRequest();
});Thread soni cheklangan. Agar blocking I/O ko‘p bo‘lsa, threadlar kutib qoladi.
Virtual thread executor
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
processRequest();
});
}Har task uchun virtual thread yaratiladi. Ular juda yengil.
Virtual thread qayerda foydali?
Ayniqsa blocking I/O’da:
database call
external HTTP API call
file read/write
queue consumer
microservice call
REST API backendMasalan, bitta request ichida DB va tashqi API chaqiriladi:
public UserProfile getProfile(Long userId) {
User user = userRepository.findById(userId).orElseThrow();
PaymentInfo payment = paymentClient.getPaymentInfo(userId);
return new UserProfile(user, payment);
}Bu blocking kod. Virtual threads bilan ko‘p requestni kamroq resource bilan boshqarish mumkin.
Virtual thread CPU-heavy ish uchun yechimmi?
Yo‘q.
CPU-heavy ishlar:
image processing
video encoding
cryptography
large calculation
compression
ML inferenceBunday joylarda CPU core limit bo‘ladi. Virtual thread CPU’ni ko‘paytirib bermaydi.
Spring Boot’da virtual threads
Spring Boot 3.2+ da virtual threads yoqish mumkin:
spring:
threads:
virtual:
enabled: trueBu servlet request handling va ayrim task executionlarda virtual threadlardan foydalanishga yordam beradi.
Lekin production’da yoqishdan oldin tekshirish kerak:
JDBC driver mosmi?
librarylar ThreadLocalga qattiq bog‘lanmaganmi?
synchronized bloklarda pinning yo‘qmi?
monitoring sozlanganmi?
load test qilinganmi?16. Virtual threads va ThreadLocal
Virtual threadlar bilan ThreadLocal ishlaydi, lekin ehtiyot bo‘lish kerak. Juda ko‘p virtual thread bo‘lsa, har birida katta object saqlash memory muammosi qilishi mumkin.
Yomon:
private static final ThreadLocal<byte[]> buffer =
ThreadLocal.withInitial(() -> new byte[1024 * 1024]);Agar juda ko‘p virtual thread bo‘lsa, memory katta ketadi.
17. Structured Concurrency
Java 21'da Structured Concurrency preview sifatida bor. G‘oyasi: parallel tasklarni tartibli boshqarish.
Masalan:
User data olish
Order data olish
Payment data olishBular bir request doirasida parallel bajariladi. Agar bittasi fail bo‘lsa, qolganlarini cancel qilish kerak bo‘lishi mumkin.
Konseptual ko‘rinish:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var user = scope.fork(() -> userClient.getUser(id));
var orders = scope.fork(() -> orderClient.getOrders(id));
scope.join();
scope.throwIfFailed();
return new Profile(user.get(), orders.get());
}Bu hali preview bo‘lgani uchun production’da ehtiyotkorlik bilan qaraladi.
18. Sequenced Collections
Java 21'da sequenced collections qo‘shildi.
Oldin List, LinkedHashSet, SortedSet kabi collectionlarda tartib bor edi, lekin umumiy interface yetishmasdi.
Endi:
SequencedCollection<String> names = new ArrayList<>();
names.addFirst("Ali");
names.addLast("Vali");
String first = names.getFirst();
String last = names.getLast();Bu hamma loyihada darrov ishlatiladigan feature emas, lekin Java 21 API’sini bilish uchun foydali.
19. Modern Java real Spring Boot misol
Keling, user registration uchun modern Java uslubida yozamiz.
Request record
public record RegisterRequest(
@NotBlank String name,
@Email String email,
@Pattern(regexp = "^\\+998\\d{9}$") String phone
) {
}Response record
public record UserDto(
Long id,
String name,
String email,
String phone
) {
public static UserDto from(User user) {
return new UserDto(
user.getId(),
user.getName(),
user.getEmail(),
user.getPhone()
);
}
}Service
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public UserDto register(RegisterRequest request) {
userRepository.findByEmail(request.email())
.ifPresent(user -> {
throw new IllegalStateException("Email already exists");
});
var user = new User(
request.name(),
request.email(),
request.phone()
);
var saved = userRepository.save(user);
return UserDto.from(saved);
}
}Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/register")
public ResponseEntity<UserDto> register(@Valid @RequestBody RegisterRequest request) {
var response = userService.register(request);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
}Bu yerda ishlatilgan modern Java:
record
var
Optional
validation annotations
static factory mapping20. Real misol: sealed error model
API errorlarni tartibli model qilish:
public sealed interface AppError
permits ValidationError, NotFoundError, ConflictError {
}public record ValidationError(
List<FieldErrorDto> fields
) implements AppError {
}public record NotFoundError(
String resource,
Long id
) implements AppError {
}public record ConflictError(
String message
) implements AppError {
}Handler:
public ErrorResponse toResponse(AppError error) {
return switch (error) {
case ValidationError validation -> new ErrorResponse(
"VALIDATION_ERROR",
validation.fields().toString()
);
case NotFoundError notFound -> new ErrorResponse(
"NOT_FOUND",
notFound.resource() + " not found: " + notFound.id()
);
case ConflictError conflict -> new ErrorResponse(
"CONFLICT",
conflict.message()
);
};
}Compiler barcha error typelar qamrab olinganini tekshiradi.
21. Java 11, 17, 21 bo‘yicha qisqa ajratish
Java 11
Muhimlari:
HttpClient
String.isBlank()
String.strip()
String.lines()
String.repeat()
var lambda parameters
Files.readString/writeStringMisol:
String content = Files.readString(Path.of("data.txt"));
Files.writeString(Path.of("out.txt"), content);Java 17
Ko‘p enterprise loyihalar uchun kuchli LTS versiya.
Muhimlari:
Records
Sealed classes
Pattern matching for instanceof
Text blocks
Switch expressions
Helpful NPEJava 17 hozir ko‘p Spring Boot loyihalarda minimum sifatida ishlatiladi.
Java 21
Yangi kuchli LTS.
Muhimlari:
Virtual threads
Pattern matching for switch
Sequenced collections
Record patterns preview
Structured concurrency preview
Scoped values previewBackend uchun eng kattasi: Virtual threads.
22. Qaysi feature’ni qachon ishlatish kerak?
Holat | Modern Java yechim |
|---|---|
DTO kerak |
|
Ko‘p qatorli SQL/JSON kerak | Text Block |
Object type tekshirish kerak | Pattern matching |
Enum asosida qiymat qaytarish | Switch expression |
Natija turlari cheklangan | Sealed interface/class |
Local type juda aniq |
|
Blocking I/O ko‘p | Virtual threads |
Immutable constant list |
|
23. Noto‘g‘ri ishlatishdan ehtiyot bo‘lish
varni hamma joyga tiqish
Yomon:
var x = service.doSomething();Yaxshi:
PaymentResponse response = paymentService.createPayment(request);Record’ni entity qilish
Yomon:
@Entity
public record Product(Long id, String name) {
}Yaxshi:
@Entity
public class Product {
}public record ProductDto(Long id, String name) {
}Virtual threadni hamma muammoning yechimi deb o‘ylash
Virtual threads:
blocking I/O uchun samarali
CPU-heavy ish uchun sehr emasPattern matching bilan murakkab business logicni tiqish
Yomon:
return switch (obj) {
case A a -> // 40 qator logic
case B b -> // 50 qator logic
};Yaxshi:
return switch (command) {
case CreateOrderCommand c -> createOrderHandler.handle(c);
case CancelOrderCommand c -> cancelOrderHandler.handle(c);
};24. Interview savollari
var nima?
Local variable type inference. Compiler type’ni o‘zi aniqlaydi. Field yoki method parameter uchun ishlamaydi.
Record nima?
Immutable’ga yaqin data carrier class. Constructor, accessor, equals, hashCode, toString avtomatik yaratiladi.
Record entity sifatida ishlatiladimi?
Odatda yo‘q. JPA entity uchun class ishlatish yaxshiroq. Record DTO uchun qulay.
Text block nima?
Ko‘p qatorli string yozish imkoniyati. SQL, JSON, HTML, test requestlarda qulay.
Pattern matching nima beradi?
Type check va castni soddalashtiradi.
Sealed class nima?
Qaysi classlar extend/implement qila olishini cheklaydi.
Virtual thread nima?
Yengil thread modeli. Ko‘p blocking I/O tasklarni kamroq resource bilan bajarishga yordam beradi.
Virtual thread CPU-heavy taskni tezlashtiradimi?
Yo‘q. CPU-heavy ish CPU core bilan cheklanadi.
stream().toList() va Collectors.toList() farqi?
stream().toList() unmodifiable list qaytarishi mumkin. Mutable list kerak bo‘lsa, Collectors.toCollection(ArrayList::new) ishlatish mumkin.
Java 17 va Java 21 orasida backend uchun eng katta farq nima?
Java 21'da virtual threads va pattern matching for switch stable bo‘lgani katta farq.
25. Middle Developer checklist
Modern Java 11-21 bo‘yicha siz quyidagilarni bilishingiz kerak:
var qachon ishlatish/qachon ishlatmaslik
Text Blocks bilan SQL/JSON yozish
Record bilan DTO yozish
Record constructor validation
Pattern matching for instanceof
Switch expression
Pattern matching for switch
Sealed classes/interfaces
Optional to‘g‘ri ishlatish
List.of/Set.of/Map.of
Stream.toList farqi
String API yangiliklari
HttpClient basics
Virtual threads
Virtual threads qachon foydali/qachon emas
Spring Boot’da virtual threads configQisqa xulosa
Modern Java 11-21 Middle developerga kodni ancha toza va productionga mos yozishga yordam beradi.
Eng ko‘p ishlatiladiganlari:
record
text block
switch expression
pattern matching
var
List.of / Set.of / Map.of
virtual threadsJunior shunday yozishi mumkin:
public class UserDto {
private Long id;
private String name;
private String email;
// constructor, getter, setter...
}Middle modern Java bilan shunday yozadi:
public record UserDto(
Long id,
String name,
String email
) {
}