5 kesalahan sing ditindakake dening 99% pangembang Java
Sumber:
Sedheng Ing kirim iki, sampeyan bakal sinau babagan kesalahan sing paling umum sing ditindakake dening pangembang Java. Minangka programmer Jawa, aku ngerti carane ala iku kanggo nglampahi akèh wektu kanggo ndandani kewan omo ing kode. Kadhangkala iki njupuk sawetara jam. Nanging, akeh kesalahan sing katon amarga pangembang ora nggatekake aturan dhasar - yaiku, iki minangka kesalahan tingkat rendah. Dina iki kita bakal nliti sawetara kesalahan coding umum lan banjur nerangake carane ndandani. Muga-muga iki mbantu sampeyan ngindhari masalah ing karya saben dina.
Mbandhingake obyek nggunakake Objects.equals
Aku nganggep sampeyan wis kenal karo metode iki. Akeh pangembang sing kerep nggunakake. Teknik iki, sing dikenalake ing JDK 7, mbantu sampeyan mbandhingake obyek kanthi cepet lan kanthi efektif ngindhari pamriksan null pointer sing ngganggu. Nanging cara iki kadhangkala salah digunakake. Mangkene maksudku:
Long longValue = 123L;
System.out.println(longValue==123);
System.out.println(Objects.equals(longValue,123));
Napa ngganti
== karo
Objects.equals () ngasilake asil sing salah? Iki amarga kompiler
== bakal entuk jinis data dhasar sing cocog karo jinis kemasan
longValue banjur mbandhingake karo jinis data dhasar kasebut. Iki padha karo compiler kanthi otomatis ngowahi konstanta menyang jinis data perbandingan dhasar. Sawise nggunakake metode
Objects.equals () , jinis data dhasar standar saka pancet compiler
int . Ing ngisor iki kode sumber
kanggo Objects.equals () ngendi
a.equals (b) nggunakake
Long.equals () lan nemtokake jinis obyek. Iki kedadeyan amarga kompiler nganggep manawa konstanta saka jinis
int , mula asil perbandingan kasebut kudu palsu.
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
public boolean equals(Object obj) {
if (obj instanceof Long) {
return value == ((Long)obj).longValue();
}
return false;
}
Ngerti alasane, ndandani kesalahan iku gampang banget. Cukup ngumumake jinis data saka konstanta, kaya
Objects.equals(longValue,123L) . Masalah ing ndhuwur ora bakal muncul yen logika ketat. Sing kudu ditindakake yaiku ngetutake aturan pemrograman sing jelas.
Format tanggal sing salah
Ing pangembangan saben dinten, sampeyan asring kudu ngganti tanggal, nanging akeh wong nggunakake format sing salah, sing ndadékaké perkara sing ora dikarepake. Iki contone:
Instant instant = Instant.parse("2021-12-31T00:00:00.00Z");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
System.out.println(formatter.format(instant));
Iki nggunakake format
YYYY-MM-dd kanggo ngganti tanggal saka 2021 dadi 2022. Sampeyan ora kudu nglakoni. Kenging punapa? Iki amarga pola
Java DateTimeFormatter "YYYY" adhedhasar standar ISO-8601, sing nemtokake taun minangka Kamis saben minggu. Nanging tanggal 31 Desember 2021 tiba ing dina Jumuah, mula program kasebut salah nuduhake 2022. Kanggo ngindhari iki, sampeyan kudu nggunakake format
yyyy-MM-dd kanggo ngowahi format tanggal . Kesalahan iki jarang kedadeyan, mung karo tekane taun anyar. Nanging ing perusahaanku nyebabake kegagalan produksi.
Nggunakake ThreadLocal ing ThreadPool
Yen sampeyan nggawe
variabel ThreadLocal , thread sing ngakses variabel kasebut bakal nggawe variabel lokal thread. Kanthi cara iki sampeyan bisa nyegah masalah safety thread. Nanging, yen sampeyan nggunakake
ThreadLocal ing
blumbang thread , sampeyan kudu ati-ati. Kode sampeyan bisa ngasilake asil sing ora dikarepake. Kanggo conto prasaja, kita duwe platform e-commerce lan pangguna kudu ngirim email kanggo konfirmasi tuku produk sing wis rampung.
private ThreadLocal<User> currentUser = ThreadLocal.withInitial(() -> null);
private ExecutorService executorService = Executors.newFixedThreadPool(4);
public void executor() {
executorService.submit(()->{
User user = currentUser.get();
Integer userId = user.getId();
sendEmail(userId);
});
}
Yen kita nggunakake
ThreadLocal kanggo nyimpen informasi pangguna, kesalahan sing didhelikake bakal katon. Amarga kumpulan benang digunakake, lan benang bisa digunakake maneh, nalika nggunakake
ThreadLocal kanggo njupuk informasi pangguna, bisa uga salah nampilake informasi wong liya. Kanggo ngatasi masalah iki, sampeyan kudu nggunakake sesi.
Gunakake HashSet kanggo mbusak data duplikat
Nalika coding, kita asring mbutuhake deduplikasi. Nalika sampeyan mikir babagan deduplikasi, sing paling dhisik dipikirake yaiku nggunakake
HashSet . Nanging, panggunaan
HashSet sing ora sopan bisa nyebabake deduplikasi gagal.
User user1 = new User();
user1.setUsername("test");
User user2 = new User();
user2.setUsername("test");
List<User> users = Arrays.asList(user1, user2);
HashSet<User> sets = new HashSet<>(users);
System.out.println(sets.size());
Sawetara pembaca sing ati-ati kudu bisa ngira-ngira alasan kegagalan kasebut.
HashSet nggunakake kode hash kanggo ngakses tabel hash lan nggunakake metode sing padha kanggo nemtokake manawa obyek padha. Yen obyek sing ditetepake pangguna ora ngilangi metode kode hash lan metode
sing padha , mula metode kode hash lan metode
sing padha karo obyek induk bakal digunakake kanthi standar. Iki bakal nyebabake
HashSet nganggep manawa ana rong obyek sing beda, nyebabake deduplikasi gagal.
Ngilangi benang blumbang "dipangan".
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(()->{
double result = 10/0;
});
Kode ndhuwur simulates skenario ngendi pangecualian di buwang ing blumbang thread. Kode bisnis kudu nganggep macem-macem kahanan, mula kemungkinan bakal mbuwang
RuntimeException sakperangan alesan . Nanging yen ora ana penanganan khusus ing kene, pangecualian iki bakal "dipangan" dening blumbang benang. Lan sampeyan ora bakal duwe cara kanggo mriksa sabab saka pangecualian. Mulane, paling apik kanggo nyekel pangecualian ing blumbang proses.
Strings ing Jawa - tampilan njero
Sumber:
Sedheng Penulis artikel iki mutusake kanggo ndeleng kanthi rinci babagan nggawe, fungsi lan fitur senar ing Jawa.
cipta
Senar ing Jawa bisa digawe kanthi rong cara: kanthi implisit, minangka string literal, lan kanthi eksplisit, nggunakake tembung kunci
anyar . String literals minangka karakter sing dilebokake ing tanda kutip ganda.
String literal = "Michael Jordan";
String object = new String("Michael Jordan");
Senajan loro Pranyatan nggawe obyek senar, ana prabédan ing carane loro obyek iki dumunung ing memori numpuk.
Perwakilan internal
Sadurungé, senar disimpen ing wangun
char [] , tegesé saben karakter minangka unsur kapisah ing array karakter. Wiwit padha diwakili ing format enkoding karakter
UTF-16 , iki tegese saben karakter njupuk rong bita memori. Iki ora bener banget, amarga statistik panggunaan nuduhake manawa obyek senar mung kalebu aksara
Latin-1 . Aksara Latin-1 bisa diwakili nggunakake siji bait memori, sing bisa nyuda panggunaan memori kanthi signifikan - nganti 50%. Fitur string internal anyar dileksanakake minangka bagean saka release JDK 9 adhedhasar
JEP 254 sing diarani Compact Strings. Ing rilis iki,
char[] diganti dadi
byte[] lan kolom gendera encoder ditambahake kanggo makili enkoding sing digunakake (Latin-1 utawa UTF-16). Sawise iki, enkoding dumadi adhedhasar isi senar. Yen nilai kasebut mung ngemot karakter Latin-1, mula enkoding Latin-1 digunakake ( kelas
StringLatin1 ) utawa enkoding UTF-16 digunakake ( kelas
StringUTF16 ).
Alokasi memori
Kaya sing wis kasebut sadurunge, ana prabédan ing cara memori diparengake kanggo obyek kasebut ing tumpukan. Nggunakake tembung kunci anyar sing eksplisit cukup gampang amarga JVM nggawe lan ngalokasi memori kanggo variabel ing tumpukan. Mulane, nggunakake string literal nderek proses disebut interning. String interning yaiku proses nglebokake string menyang blumbang. Iku nggunakake cara kanggo nyimpen mung siji salinan saben nilai string individu, kang kudu immutable. Nilai individu disimpen ing kolam renang String Intern. Kolam iki minangka toko
Hashtable sing nyimpen referensi kanggo saben obyek senar sing digawe nggunakake literal lan hash. Sanajan nilai senar ana ing tumpukan, referensi kasebut bisa ditemokake ing blumbang internal. Iki bisa gampang diverifikasi nggunakake eksperimen ing ngisor iki. Ing kene kita duwe rong variabel kanthi nilai sing padha:
String firstName1 = "Michael";
String firstName2 = "Michael";
System.out.println(firstName1 == firstName2);
Sajrone eksekusi kode, nalika JVM ketemu
firstName1 , katon munggah nilai senar ing blumbang senar internal
Michael . Yen ora bisa nemokake, banjur entri anyar digawe kanggo obyek ing blumbang internal. Nalika eksekusi tekan
firstName2 , proses kasebut diulang maneh lan wektu iki nilai kasebut bisa ditemokake ing blumbang adhedhasar variabel
firstName1 . Kanthi cara iki, tinimbang duplikat lan nggawe entri anyar, pranala sing padha bali. Mulane, kondisi kesetaraan puas. Ing sisih liya, yen variabel kanthi nilai
Michael digawe nggunakake tembung kunci anyar, ora ana interning lan kondisi kesetaraan ora puas.
String firstName3 = new String("Michael");
System.out.println(firstName3 == firstName2);
Interning bisa digunakake karo
firstName3 intern () cara , sanajan iki ora biasane disenengi.
firstName3 = firstName3.intern();
System.out.println(firstName3 == firstName2);
Interning uga bisa kedadeyan nalika nggabungake rong literal string nggunakake operator
+ .
String fullName = "Michael Jordan";
System.out.println(fullName == "Michael " + "Jordan");
Ing kene kita bisa ndeleng manawa ing wektu kompilasi, kompiler nambahake literal lan mbusak operator
+ saka ekspresi kasebut kanggo mbentuk senar siji kaya ing ngisor iki. Ing runtime, loro
fullName lan "ditambahake literal" interned lan kondisi podo wareg.
System.out.println(fullName == "Michael Jordan");
Podo
Saka eksperimen ing ndhuwur, sampeyan bisa ndeleng manawa mung string literal sing diintern kanthi standar. Nanging, aplikasi Jawa mesthi ora mung duwe string literal, amarga bisa uga nampa string saka macem-macem sumber. Mula, nggunakake operator kesetaraan ora dianjurake lan bisa ngasilake asil sing ora dikarepake. Pengujian kesetaraan mung kudu ditindakake kanthi metode
sing padha . Nindakake kesetaraan adhedhasar nilai senar tinimbang alamat memori sing disimpen.
System.out.println(firstName1.equals(firstName2));
System.out.println(firstName3.equals(firstName2));
Ana uga versi rada diowahi saka cara equals disebut
equalsIgnoreCase . Bisa uga migunani kanggo tujuan sing ora sensitif huruf cilik.
String firstName4 = "miCHAEL";
System.out.println(firstName4.equalsIgnoreCase(firstName1));
Imutabilitas
String ora bisa diganti, tegese kahanan internal ora bisa diganti sawise digawe. Sampeyan bisa ngganti Nilai saka variabel, nanging ora Nilai saka senar dhewe. Saben cara saka kelas
String sing ngurusi manipulasi obyek (umpamane,
concat ,
substring ) ngasilake salinan anyar saka nilai tinimbang nganyari nilai sing wis ana.
String firstName = "Michael";
String lastName = "Jordan";
firstName.concat(lastName);
System.out.println(firstName);
System.out.println(lastName);
Kaya sing sampeyan ngerteni, ora ana owah-owahan ing variabel apa wae:
firstName utawa
lastName . Metode kelas
string ora ngganti negara internal, nggawe salinan asil anyar lan ngasilake asil kaya ing ngisor iki.
firstName = firstName.concat(lastName);
System.out.println(firstName);
GO TO FULL VERSION