Java asoslari 9-qism. Java 8+

30.06.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Java tili | 27 daqiqa o'qish

Java 8+ features — Java’ni eski “faqat OOP” uslubidan zamonaviy, qisqa, funksional va qulay yozish uslubiga olib chiqqan imkoniyatlar.

Bu bo‘limga quyidagilar kiradi: Lambda expressions, Functional interfaces, Stream API, Optional, Method references, Default & static interface methods, Date/Time API (java.time).


1. Java 8 nega muhim?

Java 8’dan oldin ko‘p kodlar juda uzun yozilardi.

Masalan, ro‘yxatdagi ismlarni chiqarish:

List<String> names = List.of("Ali", "Vali", "Hasan");

for (String name : names) {
    System.out.println(name);
}

Java 8’dan keyin buni qisqaroq yozish mumkin:

names.forEach(name -> System.out.println(name));

Yoki yanada qisqa:

names.forEach(System.out::println);

Java 8+ sizga quyidagilarni beradi:

  • kamroq boilerplate kod;

  • collectionlar bilan qulay ishlash;

  • filter, map, sort, group qilish;

  • null bilan xavfsizroq ishlash;

  • vaqt/sana bilan to‘g‘ri ishlash;

  • funksional programming elementlari.


2. Lambda Expression

Lambda — methodni qisqa ko‘rinishda yozish usuli.

Oddiy ko‘rinishi:

(parameter) -> action

Masalan:

name -> System.out.println(name)

Bu degani:

name degan qiymat keladi, uni print qilamiz

2.1 Lambda oldidan qanday yozilardi?

Java 8’dan oldin anonymous class ishlatilardi.

Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("Task ishladi");
    }
};

Java 8 bilan:

Runnable task = () -> System.out.println("Task ishladi");

Bu yerda:

  • () — parameter yo‘q;

  • -> — lambda belgisi;

  • System.out.println(...) — bajariladigan ish.


2.2 Lambda misollar

Bitta parameter

Consumer<String> printer = name -> System.out.println(name);

printer.accept("Ali");

Ikkita parameter

BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;

System.out.println(sum.apply(10, 20));

Natija:

30

Bir nechta qatorli lambda

Consumer<String> printer = name -> {
    System.out.println("Name:");
    System.out.println(name);
};

Agar lambda ichida bir nechta qator bo‘lsa, {} ishlatiladi.


3. Functional Interface

Functional interface — ichida faqat bitta abstract method bo‘lgan interface.

Masalan:

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

Bu interface lambda bilan ishlatiladi:

Calculator sum = (a, b) -> a + b;

int result = sum.calculate(10, 20);

System.out.println(result);

Natija:

30

3.1 @FunctionalInterface nima qiladi?

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

Bu annotation Java’ga aytadi:

Bu interface functional interface bo‘lishi kerak.

Agar ikkinchi abstract method qo‘shib yuborsangiz, compile error beradi.

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);

    int minus(int a, int b); // xato
}

4. Tayyor functional interfacelar

Java’da tayyor functional interfacelar bor. Eng keraklilari:

Interface

Ma’nosi

Method

Predicate<T>

shart tekshiradi

test()

Function<T, R>

bir type’dan boshqa type qaytaradi

apply()

Consumer<T>

qiymat oladi, lekin qaytarmaydi

accept()

Supplier<T>

qiymat ishlab chiqaradi

get()

UnaryOperator<T>

bitta type olib, o‘sha type qaytaradi

apply()

BinaryOperator<T>

ikkita bir xil type olib, bitta natija qaytaradi

apply()


4.1 Predicate

Predicate — shart tekshiradi. Natija true yoki false.

Predicate<Integer> isEven = number -> number % 2 == 0;

System.out.println(isEven.test(10));
System.out.println(isEven.test(7));

Natija:

true
false

Real misol:

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

List<Integer> evenNumbers = numbers.stream()
        .filter(number -> number % 2 == 0)
        .toList();

System.out.println(evenNumbers);

Natija:

[2, 4, 6]

4.2 Function

Function<T, R> — bitta qiymat olib, boshqa qiymat qaytaradi.

Function<String, Integer> lengthFunction = text -> text.length();

System.out.println(lengthFunction.apply("Java"));

Natija:

4

Real misol:

List<String> names = List.of("Ali", "Vali", "Hasan");

List<Integer> lengths = names.stream()
        .map(name -> name.length())
        .toList();

System.out.println(lengths);

Natija:

[3, 4, 5]

4.3 Consumer

Consumer<T> — qiymat oladi, lekin hech narsa qaytarmaydi.

Consumer<String> printer = text -> System.out.println(text);

printer.accept("Hello Java");

Real misol:

List<String> names = List.of("Ali", "Vali", "Hasan");

names.forEach(name -> System.out.println(name));

4.4 Supplier

Supplier<T> — parameter olmaydi, qiymat qaytaradi.

Supplier<Double> randomSupplier = () -> Math.random();

System.out.println(randomSupplier.get());

Real misol:

Supplier<LocalDateTime> nowSupplier = () -> LocalDateTime.now();

System.out.println(nowSupplier.get());

5. Stream API

Stream API — collection ichidagi ma’lumotlarni functional uslubda qayta ishlash uchun ishlatiladi.

Stream yordamida:

  • filter qilish;

  • map qilish;

  • sort qilish;

  • count qilish;

  • group qilish;

  • reduce qilish;

  • listga yig‘ish;

mumkin.


5.1 Oddiy stream misol

List<String> names = List.of("Ali", "Vali", "Hasan", "Aziz");

List<String> result = names.stream()
        .filter(name -> name.startsWith("A"))
        .toList();

System.out.println(result);

Natija:

[Ali, Aziz]

Bu yerda:

names.stream()

collectionni streamga aylantiradi.

.filter(name -> name.startsWith("A"))

faqat A bilan boshlanadiganlarni qoldiradi.

.toList()

natijani listga yig‘adi.


6. Stream filter

filter — shartga mos elementlarni qoldiradi.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

List<Integer> evenNumbers = numbers.stream()
        .filter(number -> number % 2 == 0)
        .toList();

System.out.println(evenNumbers);

Natija:

[2, 4, 6]

7. Stream map

map — har bir elementni boshqa ko‘rinishga o‘zgartiradi.

List<String> names = List.of("Ali", "Vali", "Hasan");

List<String> upperNames = names.stream()
        .map(name -> name.toUpperCase())
        .toList();

System.out.println(upperNames);

Natija:

[ALI, VALI, HASAN]

7.1 Entity’dan DTO yasash

Backend’da map juda ko‘p ishlatiladi.

public class User {
    private Long id;
    private String name;

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
public class UserDto {
    private Long id;
    private String name;

    public UserDto(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

Listni DTO’ga o‘tkazish:

List<UserDto> userDtos = users.stream()
        .map(user -> new UserDto(user.getId(), user.getName()))
        .toList();

Bu real Spring Boot loyihalarda juda ko‘p ishlatiladi.


8. Stream sorted

List<Integer> numbers = List.of(5, 1, 4, 2, 3);

List<Integer> sortedNumbers = numbers.stream()
        .sorted()
        .toList();

System.out.println(sortedNumbers);

Natija:

[1, 2, 3, 4, 5]

Objectlarni sort qilish:

List<User> sortedUsers = users.stream()
        .sorted(Comparator.comparing(User::getName))
        .toList();

Age bo‘yicha kamayish tartibida:

List<User> sortedUsers = users.stream()
        .sorted(Comparator.comparing(User::getAge).reversed())
        .toList();

9. Stream forEach

forEach — har bir element ustida amal bajaradi.

List<String> names = List.of("Ali", "Vali", "Hasan");

names.stream()
        .forEach(name -> System.out.println(name));

Yoki:

names.forEach(name -> System.out.println(name));

Yanada qisqa:

names.forEach(System.out::println);

Muhim: forEach odatda natija qaytarmaydi. Faqat amal bajaradi.


10. Stream count

List<String> names = List.of("Ali", "Vali", "Hasan", "Aziz");

long count = names.stream()
        .filter(name -> name.startsWith("A"))
        .count();

System.out.println(count);

Natija:

2

11. Stream findFirst

List<String> names = List.of("Ali", "Vali", "Hasan");

Optional<String> first = names.stream()
        .filter(name -> name.startsWith("A"))
        .findFirst();

System.out.println(first.orElse("Topilmadi"));

Natija:

Ali

findFirst() natijasi Optional bo‘ladi. Chunki element topilmasligi ham mumkin.


12. Stream anyMatch, allMatch, noneMatch

anyMatch

Kamida bittasi mos kelsa true.

boolean hasAdult = users.stream()
        .anyMatch(user -> user.getAge() >= 18);

allMatch

Hammasi mos kelsa true.

boolean allAdults = users.stream()
        .allMatch(user -> user.getAge() >= 18);

noneMatch

Hech biri mos kelmasa true.

boolean noBlockedUsers = users.stream()
        .noneMatch(user -> user.isBlocked());

13. Stream reduce

reduce — collection ichidagi qiymatlarni bitta natijaga yig‘adi.

Masalan, sonlar yig‘indisi:

List<Integer> numbers = List.of(1, 2, 3, 4);

int sum = numbers.stream()
        .reduce(0, (a, b) -> a + b);

System.out.println(sum);

Natija:

10

Qisqaroq:

int sum = numbers.stream()
        .reduce(0, Integer::sum);

14. Collectors

Collectors — stream natijasini yig‘ish uchun ishlatiladi.

Java 16+ da ko‘p joyda .toList() ishlatsa bo‘ladi:

List<String> result = names.stream()
        .filter(name -> name.startsWith("A"))
        .toList();

Lekin Java 8’da odatda bunday yoziladi:

List<String> result = names.stream()
        .filter(name -> name.startsWith("A"))
        .collect(Collectors.toList());

14.1 Setga yig‘ish

Set<String> uniqueNames = names.stream()
        .collect(Collectors.toSet());

14.2 Mapga yig‘ish

Map<Long, User> usersById = users.stream()
        .collect(Collectors.toMap(
                User::getId,
                user -> user
        ));

Bu real backend’da juda foydali.

Masalan, List<User> bor. Sizga id -> user ko‘rinishida Map kerak.


14.3 groupingBy

groupingBy — ma’lumotlarni guruhlash.

Masalan, userlarni age bo‘yicha guruhlash:

Map<Integer, List<User>> usersByAge = users.stream()
        .collect(Collectors.groupingBy(User::getAge));

Orderlarni status bo‘yicha guruhlash:

Map<OrderStatus, List<Order>> ordersByStatus = orders.stream()
        .collect(Collectors.groupingBy(Order::getStatus));

Natija taxminan:

NEW -> [order1, order2]
PAID -> [order3, order4]
CANCELLED -> [order5]

15. Stream API’da muhim tushuncha

Stream operationlar ikki turga bo‘linadi:

Intermediate operations

Bular streamni qayta ishlaydi, lekin darhol ishga tushmaydi:

  • filter

  • map

  • sorted

  • distinct

  • limit

  • skip

Terminal operations

Bular streamni ishga tushiradi:

  • toList

  • collect

  • forEach

  • count

  • findFirst

  • reduce

  • anyMatch

Misol:

List<String> result = names.stream()
        .filter(name -> name.startsWith("A"))
        .map(String::toUpperCase)
        .toList();

Bu yerda:

filter -> intermediate
map -> intermediate
toList -> terminal

Terminal operation bo‘lmasa, stream ishlamaydi.


16. Method Reference

Method reference — lambda’ni yanada qisqa yozish usuli.

Lambda:

names.forEach(name -> System.out.println(name));

Method reference:

names.forEach(System.out::println);

16.1 Method reference turlari

Static method reference

Function<String, Integer> parser = Integer::parseInt;

Bu shunga teng:

Function<String, Integer> parser = text -> Integer.parseInt(text);

Instance method reference

List<String> upperNames = names.stream()
        .map(String::toUpperCase)
        .toList();

Bu shunga teng:

.map(name -> name.toUpperCase())

Constructor reference

Supplier<ArrayList<String>> listSupplier = ArrayList::new;

Bu shunga teng:

Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

17. Optional

Optional — qiymat bor yoki yo‘qligini xavfsiz ifodalash uchun ishlatiladi.

U null o‘rnini to‘liq bosmaydi, lekin method natijasida “topilishi ham, topilmasligi ham mumkin” degan holatni aniq ko‘rsatadi.


17.1 Optional yaratish

Optional<String> name = Optional.of("Ali");

Bo‘sh Optional:

Optional<String> empty = Optional.empty();

Null bo‘lishi mumkin bo‘lgan qiymatdan:

String text = getName();

Optional<String> optionalText = Optional.ofNullable(text);

ofNullable null kelsa xato bermaydi, Optional.empty() qiladi.


17.2 Optional ishlatish

Yomon usul:

User user = userRepository.findById(1L);

if (user != null) {
    System.out.println(user.getName());
}

Yaxshi usul:

Optional<User> optionalUser = userRepository.findById(1L);

optionalUser.ifPresent(user -> System.out.println(user.getName()));

17.3 orElse

String name = optionalName.orElse("Noma'lum");

Agar qiymat bo‘lsa — o‘sha qiymat. Bo‘lmasa — "Noma'lum".


17.4 orElseThrow

Spring Boot’da juda ko‘p ishlatiladi:

User user = userRepository.findById(id)
        .orElseThrow(() -> new RuntimeException("User topilmadi"));

Bu degani:

User topilsa qaytar. Topilmasa exception ot.


17.5 Optional bilan map

Optional<String> userName = userRepository.findById(id)
        .map(User::getName);

Agar user topilsa, uning name’ini oladi. Topilmasa, empty qoladi.


17.6 Optional xatolari

Yomon:

Optional<User> user = userRepository.findById(id);

if (user.isPresent()) {
    System.out.println(user.get().getName());
}

Bu ishlaydi, lekin ko‘pincha chiroyli emas.

Yaxshiroq:

userRepository.findById(id)
        .ifPresent(user -> System.out.println(user.getName()));

Yoki kerak bo‘lsa:

User user = userRepository.findById(id)
        .orElseThrow(() -> new RuntimeException("User topilmadi"));

18. Default methods in interface

Java 8’dan boshlab interface ichida tayyor method yozish mumkin.

public interface PaymentService {
    void pay(double amount);

    default void printInfo() {
        System.out.println("Payment service");
    }
}

Implementation class printInfo()ni yozmasa ham bo‘ladi.

public class ClickPaymentService implements PaymentService {
    @Override
    public void pay(double amount) {
        System.out.println("Click orqali to'landi");
    }
}

Ishlatish:

PaymentService service = new ClickPaymentService();

service.pay(100_000);
service.printInfo();

18.1 Nega default method kerak?

Asosiy sabab:

Eski interface’ga yangi method qo‘shilganda, eski implementation classlar buzilib ketmasin.

Masalan, sizda interface bor:

public interface ReportService {
    void generate();
}

Keyin unga yangi method qo‘shmoqchisiz:

public interface ReportService {
    void generate();

    default void exportPdf() {
        System.out.println("PDF export qilindi");
    }
}

Endi eski classlar exportPdf()ni majburiy override qilishi shart emas.


19. Static methods in interface

Interface ichida static method ham yozish mumkin.

public interface MathUtils {
    static int square(int number) {
        return number * number;
    }
}

Ishlatish:

int result = MathUtils.square(5);

System.out.println(result);

Natija:

25

Static interface method obyekt orqali emas, interface nomi orqali chaqiriladi.


20. Date/Time API — java.time

Java 8’dan oldin Date va Calendar ishlatilardi. Ular noqulay va xatoga moyil edi.

Java 8’da yangi java.time API keldi.

Eng kerakli classlar:

Class

Ma’nosi

LocalDate

faqat sana

LocalTime

faqat vaqt

LocalDateTime

sana + vaqt

ZonedDateTime

timezone bilan sana/vaqt

Instant

aniq vaqt nuqtasi

Duration

vaqt oralig‘i

Period

sana oralig‘i


20.1 LocalDate

LocalDate today = LocalDate.now();

System.out.println(today);

Natija:

2026-05-20

Sana yaratish:

LocalDate birthDate = LocalDate.of(2000, 5, 10);

20.2 LocalTime

LocalTime now = LocalTime.now();

System.out.println(now);

20.3 LocalDateTime

LocalDateTime now = LocalDateTime.now();

System.out.println(now);

Bu sana va vaqtni beradi, lekin timezone saqlamaydi.


20.4 Sana qo‘shish/ayirish

LocalDate today = LocalDate.now();

LocalDate tomorrow = today.plusDays(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate yesterday = today.minusDays(1);

20.5 DateTimeFormatter

LocalDate date = LocalDate.now();

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");

String formatted = date.format(formatter);

System.out.println(formatted);

Natija:

20.05.2026

Stringdan date yasash:

String text = "20.05.2026";

LocalDate date = LocalDate.parse(
        text,
        DateTimeFormatter.ofPattern("dd.MM.yyyy")
);

21. Real backend misol: Order filter

Tasavvur qiling, orderlar ro‘yxati bor.

public class Order {
    private Long id;
    private String customerName;
    private OrderStatus status;
    private int amount;
    private LocalDateTime createdAt;

    public Order(Long id, String customerName, OrderStatus status, int amount, LocalDateTime createdAt) {
        this.id = id;
        this.customerName = customerName;
        this.status = status;
        this.amount = amount;
        this.createdAt = createdAt;
    }

    public Long getId() {
        return id;
    }

    public String getCustomerName() {
        return customerName;
    }

    public OrderStatus getStatus() {
        return status;
    }

    public int getAmount() {
        return amount;
    }

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }
}

Status enum:

public enum OrderStatus {
    NEW,
    PAID,
    CANCELLED
}

Orderlarni filter qilish:

List<Order> paidOrders = orders.stream()
        .filter(order -> order.getStatus() == OrderStatus.PAID)
        .toList();

Summani hisoblash:

int totalAmount = orders.stream()
        .filter(order -> order.getStatus() == OrderStatus.PAID)
        .mapToInt(Order::getAmount)
        .sum();

Eng oxirgi orderni topish:

Optional<Order> latestOrder = orders.stream()
        .max(Comparator.comparing(Order::getCreatedAt));

Status bo‘yicha guruhlash:

Map<OrderStatus, List<Order>> ordersByStatus = orders.stream()
        .collect(Collectors.groupingBy(Order::getStatus));

22. Stream API’da ehtiyot bo‘lish kerak bo‘lgan joylar

22.1 Juda murakkab stream yozish

Yomon:

List<String> result = users.stream()
        .filter(u -> u.getAge() > 18)
        .filter(u -> !u.isBlocked())
        .map(u -> u.getOrders())
        .flatMap(o -> o.stream())
        .filter(o -> o.getAmount() > 100000)
        .map(o -> o.getProduct().getName())
        .distinct()
        .sorted()
        .toList();

Bu ishlaydi, lekin o‘qish qiyin.

Bunday holatda oddiy methodlarga ajratgan yaxshi.


22.2 Stream ichida side effect qilish

Yomon:

List<String> result = new ArrayList<>();

users.stream()
        .filter(user -> user.getAge() > 18)
        .forEach(user -> result.add(user.getName()));

Yaxshi:

List<String> result = users.stream()
        .filter(user -> user.getAge() > 18)
        .map(User::getName)
        .toList();

22.3 Null qiymatlar

Agar list ichida null bo‘lsa:

List<String> names = Arrays.asList("Ali", null, "Vali");

List<String> upperNames = names.stream()
        .map(String::toUpperCase)
        .toList();

Bu NullPointerException beradi.

Yaxshi:

List<String> upperNames = names.stream()
        .filter(Objects::nonNull)
        .map(String::toUpperCase)
        .toList();

23. Java 8+ features qayerda ko‘p ishlatiladi?

Spring Boot backend’da:

userRepository.findById(id)
        .orElseThrow(() -> new RuntimeException("User topilmadi"));
List<UserDto> users = userRepository.findAll().stream()
        .map(userMapper::toDto)
        .toList();
Map<Long, Product> productsById = products.stream()
        .collect(Collectors.toMap(Product::getId, product -> product));
orders.stream()
        .filter(order -> order.getStatus() == OrderStatus.PAID)
        .mapToInt(Order::getAmount)
        .sum();

24. Junior uchun eng muhim qismlar

Mavzu

Bilish darajasi

Lambda

Majburiy

Functional interface

Majburiy

Predicate, Function, Consumer, Supplier

Kerak

Stream filter, map, toList

Majburiy

Stream sorted, count, findFirst

Kerak

Collectors.toMap, groupingBy

Kerak

Optional

Majburiy

Method reference

Kerak

java.time

Majburiy

Default/static interface methods

Asosiy tushuncha yetadi


25. Amaliy mashq

Vazifa: User filter system

User class yarating:

public class User {
    private Long id;
    private String name;
    private int age;
    private boolean active;

    public User(Long id, String name, int age, boolean active) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.active = active;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public boolean isActive() {
        return active;
    }
}

List yarating:

List<User> users = List.of(
        new User(1L, "Ali", 25, true),
        new User(2L, "Vali", 17, true),
        new User(3L, "Hasan", 30, false),
        new User(4L, "Aziz", 22, true)
);

Quyidagilarni bajaring:

  1. Faqat active userlarni oling.

  2. Faqat 18 yoshdan kattalarni oling.

  3. User name’larini List<String> qilib oling.

  4. Userlarni age bo‘yicha sort qiling.

  5. Map<Long, User> yasang.

  6. Active userlar sonini hisoblang.

  7. Eng katta yoshli userni toping.

  8. Optional<User> orqali id = 10 bo‘lgan userni qidiring.

  9. Topilmasa "User topilmadi" exception chiqaring.

  10. Bugungi sanani dd.MM.yyyy formatda chiqaring.


Xulosa

Java 8+ features Junior Java developer uchun juda muhim.

Asosiy eslab qoling:

list.stream()
        .filter(...)
        .map(...)
        .toList();
Optional<User> user = repository.findById(id);
users.forEach(System.out::println);
LocalDate.now();
LocalDateTime.now();

Java 8+ sizga kodni:

  • qisqaroq;

  • o‘qilishi osonroq;

  • xavfsizroq;

  • functional uslubga yaqinroq;

  • backend API uchun qulayroq

qilib yozishga yordam beradi.