17-bo‘lim
Optional va null xavfsizligi
NullPointerException sabablari, Optional yaratish va ishlatish, map va flatMap, Objects yordamchilari hamda null ni kamaytirish usullari.
Ushbu bo‘lim mundarijasi
null - "bu yerda hech narsa yo'q" degani. U foydali, lekin
Java'dagi eng ko'p uchraydigan qulash sababi.
Muammo #
public class Muammo {
public static void main(String[] args) {
String ism = null;
try {
System.out.println(ism.length());
} catch (NullPointerException x) {
System.out.println("Qulash: " + x.getClass().getSimpleName());
}
}
}
Qulash: NullPointerException
null tushunchasini 1965-yilda ingliz olimi Tony Hoare kiritgan.
Keyinchalik u buni "mening bir milliard dollarlik xatom" deb atagan:
uning hisobicha, null sabab bo'lgan qulashlar, zaifliklar va
tuzatish ishlari o'nlab yillar davomida shuncha zarar keltirgan.
Java bu muammoni til darajasida hal qilmagan - String har doim
null bo'lishi mumkin. Kotlin va boshqa keyingi tillar aynan shu
kamchilikni tuzatish uchun yaratilgan.
Java'da bizda Optional va yaxshi odatlar bor.
Yordamchi xato xabarlari #
Java 14 dan NullPointerException xabari ancha aniqroq:
public class Aniq {
public static void main(String[] args) {
Talaba t = new Talaba(null);
try {
System.out.println(t.manzil().shahar().toUpperCase());
} catch (NullPointerException x) {
System.out.println("Xabar: " + x.getMessage());
}
}
}
record Manzil(String shahar) {
}
record Talaba(Manzil manzil) {
}
Xabar: Cannot invoke "Manzil.shahar()" because the return value of "Talaba.manzil()" is null
Xabar qaysi chaqiruv null qaytarganini aniq aytadi. Eski
Java'da faqat qator raqami bo'lardi va zanjirdagi qaysi bo'g'in
aybdorligini topish qiyin edi.
Optional #
Optional<T> - "qiymat bo'lishi ham, bo'lmasligi ham mumkin" degan
quticha:
import java.util.Optional;
public class Yaratish {
public static void main(String[] args) {
Optional<String> bor = Optional.of("Namangan");
Optional<String> bosh = Optional.empty();
Optional<String> ehtimol = Optional.ofNullable(null);
System.out.println("bor: " + bor);
System.out.println("bosh: " + bosh);
System.out.println("ehtimol: " + ehtimol);
System.out.println("bor mavjudmi: " + bor.isPresent());
System.out.println("bosh bo'shmi: " + bosh.isEmpty());
}
}
bor: Optional[Namangan]
bosh: Optional.empty
ehtimol: Optional.empty
bor mavjudmi: true
bosh bo'shmi: true
| Metod | Qachon |
|---|---|
Optional.of(x) | x aniq null emas |
Optional.ofNullable(x) | x null bo'lishi mumkin |
Optional.empty() | Qiymat yo'q |
Optional.of(null) istisno tashlaydiimport java.util.Optional;
public class Ogoh {
public static void main(String[] args) {
try {
Optional.of(null);
} catch (NullPointerException x) {
System.out.println("of(null) quladi");
}
System.out.println("ofNullable(null): "
+ Optional.ofNullable(null));
}
}
of(null) quladi
ofNullable(null): Optional.empty
of null ni qabul qilmaydi - u "men aniq bilaman, bu null emas"
degan da'vo. Ishonchingiz komil bo'lmasa ofNullable ishlating.
Qiymatni olish #
import java.util.Optional;
public class Olish {
public static void main(String[] args) {
Optional<String> bor = Optional.of("Namangan");
Optional<String> bosh = Optional.empty();
System.out.println(bor.orElse("sukut"));
System.out.println(bosh.orElse("sukut"));
System.out.println(bosh.orElseGet(() -> "hisoblangan sukut"));
try {
bosh.orElseThrow(() -> new IllegalStateException("qiymat yo'q"));
} catch (IllegalStateException x) {
System.out.println("orElseThrow: " + x.getMessage());
}
bor.ifPresent(q -> System.out.println("ifPresent: " + q));
bosh.ifPresentOrElse(
q -> System.out.println("bor: " + q),
() -> System.out.println("ifPresentOrElse: qiymat yo'q"));
}
}
Namangan
sukut
hisoblangan sukut
orElseThrow: qiymat yo'q
ifPresent: Namangan
ifPresentOrElse: qiymat yo'q
get() ni ishlatmangOptional da get() metodi bor, lekin u qiymat yo'q bo'lsa
NoSuchElementException tashlaydi:
import java.util.Optional;
public class Get {
public static void main(String[] args) {
Optional<String> bosh = Optional.empty();
try {
System.out.println(bosh.get());
} catch (Exception x) {
System.out.println("get(): " + x.getClass().getSimpleName());
}
}
}
get(): NoSuchElementException
get() ishlatish Optional ning butun ma'nosini yo'qqa chiqaradi:
siz null tekshiruvini Optional tekshiruviga almashtirdingiz,
xolos.
Har doim orElse, orElseGet, orElseThrow yoki ifPresent
ishlating.
orElse va orElseGet farqi: orElse argumentni har doim
hisoblaydi, orElseGet esa faqat kerak bo'lganda. Sukut qiymat
qimmat hisoblansa - orElseGet.
map va filter #
Optional ning asosiy kuchi shu yerda:
import java.util.Optional;
public class Zanjir {
public static void main(String[] args) {
System.out.println(shaharKatta(new Talaba(new Manzil("Namangan"))));
System.out.println(shaharKatta(new Talaba(null)));
System.out.println(shaharKatta(new Talaba(new Manzil(null))));
System.out.println(shaharKatta(null));
}
static String shaharKatta(Talaba t) {
return Optional.ofNullable(t)
.map(Talaba::manzil)
.map(Manzil::shahar)
.filter(s -> !s.isBlank())
.map(String::toUpperCase)
.orElse("(manzil yo'q)");
}
}
record Manzil(String shahar) {
}
record Talaba(Manzil manzil) {
}
NAMANGAN
(manzil yo'q)
(manzil yo'q)
(manzil yo'q)
To'rt xil null holati - bitta zanjir, hech qanday if yo'q.
map ichidagi funksiya null bo'lsa umuman chaqirilmaydi.
flatMap #
Metod o'zi Optional qaytarsa, map o'rniga flatMap kerak:
import java.util.Optional;
public class FlatMap {
public static void main(String[] args) {
Ombor ombor = new Ombor();
System.out.println(ombor.topish("Husanboy")
.map(Talaba::ism)
.orElse("topilmadi"));
System.out.println(ombor.topish("Malika")
.map(Talaba::ism)
.orElse("topilmadi"));
System.out.println(ombor.topish("Husanboy")
.flatMap(Talaba::telefon)
.orElse("telefon yo'q"));
}
}
record Talaba(String ism, String raqam) {
Optional<String> telefon() {
return Optional.ofNullable(raqam);
}
}
class Ombor {
Optional<Talaba> topish(String ism) {
if (ism.equals("Husanboy")) {
return Optional.of(new Talaba("Husanboy", null));
}
return Optional.empty();
}
}
Husanboy
topilmadi
telefon yo'q
map va flatMap farqi| Funksiya qaytaradi | Ishlating | Natija |
|---|---|---|
Oddiy qiymat (String) | map | Optional<String> |
Optional<String> | flatMap | Optional<String> |
map ni Optional qaytaruvchi funksiya bilan ishlatsangiz, natija
Optional<Optional<String>> bo'lib qoladi - bu deyarli har doim
xato.
Xuddi shu qoida Stream API da ham amal qiladi (16-bo'lim).
Optional ni qayerda ishlatish #
class Talaba {
private Optional<String> telefon; // YOMON
void yoz(Optional<String> matn) { } // YOMON
}
Uch sabab:
Optionalning o'zinullbo'lishi mumkin - muammo hal bo'lmadi, faqat bir qavat qo'shildi;- U
Serializableemas - ba'zi freymvorklar bilan ishlamaydi; - Har bir obyekt uchun qo'shimcha obyekt yaratiladi.
Optional ataylab qaytish qiymati uchun yaratilgan: "bu metod
natija topmasligi mumkin" degan xabar.
| Joy | Ishlatish |
|---|---|
| Metod qaytish turi | Ha - asosiy maqsadi |
| Sinf maydoni | Yo'q - oddiy maydon va null tekshiruvi |
| Metod parametri | Yo'q - ortiqcha yuklash yoki null |
| Kolleksiya elementi | Yo'q - bo'sh kolleksiya qaytaring |
Objects yordamchilari #
import java.util.Objects;
public class Yordamchi {
public static void main(String[] args) {
String bosh = null;
String bor = "Namangan";
System.out.println("isNull: " + Objects.isNull(bosh));
System.out.println("nonNull: " + Objects.nonNull(bor));
System.out.println("equals: " + Objects.equals(bosh, bor));
System.out.println("equals(null,null): "
+ Objects.equals(null, null));
System.out.println("toString: "
+ Objects.toString(bosh, "(yo'q)"));
System.out.println("hash: "
+ (Objects.hash("a", 1) == Objects.hash("a", 1)));
System.out.println("requireNonNullElse: "
+ Objects.requireNonNullElse(bosh, "sukut"));
try {
Objects.requireNonNull(bosh, "ism berilishi shart");
} catch (NullPointerException x) {
System.out.println("requireNonNull: " + x.getMessage());
}
}
}
isNull: true
nonNull: true
equals: false
equals(null,null): true
toString: (yo'q)
hash: true
requireNonNullElse: sukut
requireNonNull: ism berilishi shart
Objects.requireNonNull ni konstruktor va ommaviy metodlar boshida
ishlating:
import java.util.Objects;
public class Tekshiruv {
public static void main(String[] args) {
System.out.println(new Talaba("Husanboy"));
try {
new Talaba(null);
} catch (NullPointerException x) {
System.out.println("Ushlandi: " + x.getMessage());
}
}
}
record Talaba(String ism) {
Talaba {
Objects.requireNonNull(ism, "ism null bo'lmasin");
}
}
Talaba[ism=Husanboy]
Ushlandi: ism null bo'lmasin
Foydasi: xato kelib chiqish joyida aniqlanadi. Aks holda null
obyekt ichida saqlanib, ancha keyin, butunlay boshqa joyda quladi -
va sababini topish qiyin bo'ladi.
Amaliy qoidalar #
| Holat | Nima qilish |
|---|---|
| Metod natija topmasligi mumkin | Optional qaytaring |
| Ro'yxat bo'sh bo'lishi mumkin | Bo'sh ro'yxat qaytaring, null emas |
| Satr yo'q | "" yoki Optional |
Argument null bo'lmasligi kerak | Objects.requireNonNull |
| Sukut qiymat bor | orElse yoki requireNonNullElse |
| Maydon | Oddiy tur, Optional emas |
import java.util.*;
public class Kolleksiya {
public static void main(String[] args) {
System.out.println("Yomon: "
+ (yomon("yo'q") == null ? "null keldi" : "ro'yxat"));
System.out.println("Yaxshi: "
+ yaxshi("yo'q").size() + " ta element");
for (String s : yaxshi("yo'q")) {
System.out.println("bu hech qachon chiqmaydi: " + s);
}
System.out.println("Sikl xavfsiz o'tdi");
}
static List<String> yomon(String q) {
return q.equals("bor") ? List.of("a") : null;
}
static List<String> yaxshi(String q) {
return q.equals("bor") ? List.of("a") : List.of();
}
}
Yomon: null keldi
Yaxshi: 0 ta element
Sikl xavfsiz o'tdi
Birinchi metoddan keyin har bir chaqiruvchi null ni tekshirishi
kerak. Ikkinchisidan keyin natijani darhol for ga berish mumkin -
bo'sh ro'yxat bo'ylab yurish xavfsiz.
Kolleksiyalar uchun Optional ham kerak emas - bo'sh kolleksiya
o'zi "hech narsa yo'q" degani.
nullo'zgaruvchiga murojaat qilib, xabar matnini o'qing.- Ikki darajali zanjirda
nullqoldirib, xabar qaysi bo'g'inni ko'rsatishini ko'ring. Optional.of,ofNullablevaemptyni yarating.Optional.of(null)yozib, istisnoni ko'ring.orElse,orElseGetvaorElseThrowni sinang.get()ni bo'shOptionalda chaqirib ko'ring.mapzanjiri bilan ichma-ichnulllarni xavfsiz o'ting.flatMapbilanOptionalqaytaruvchi metodni bog'lang.Objects.requireNonNullnirecordkonstruktorida ishlating.nullqaytaruvchi metodni bo'sh ro'yxat qaytaradigan qilib qayta yozing.
Xulosa #
- Java 14 dan
NullPointerExceptionxabari qaysi chaqiruvnullqaytarganini aytadi. Optional.ofnullqabul qilmaydi -ofNullableishlating.get()ni ishlatmang -orElse,orElseGet,orElseThrowyokiifPresent.mapzanjirinulllarni xavfsiz o'tkazadi; funksiyaOptionalqaytarsa -flatMap.Optionalfaqat qaytish turi uchun; maydon va parametrda ishlatmang.Objects.requireNonNullbilan argumentlarni kelib chiqish joyida tekshiring.- Kolleksiya uchun
Optionalemas - bo'sh kolleksiya qaytaring.
Keyingi bo'limda fayllar bilan ishlashni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.