JavaRush /Blog Java /Random-MS /Terjemahan buku. Pengaturcaraan berfungsi dalam Java. Bab...
timurnav
Tahap

Terjemahan buku. Pengaturcaraan berfungsi dalam Java. Bab 1

Diterbitkan dalam kumpulan
Saya berbesar hati untuk membantu anda mencari kesilapan dan meningkatkan kualiti terjemahan. Saya menterjemah untuk meningkatkan kemahiran bahasa Inggeris saya, dan jika anda membaca dan mencari ralat terjemahan, maka anda akan bertambah baik daripada saya. Pengarang buku itu menulis bahawa buku itu mengandaikan banyak pengalaman bekerja dengan Jawa; sejujurnya, saya sendiri tidak begitu berpengalaman, tetapi saya memahami bahan dalam buku itu. Buku ini membincangkan beberapa teori yang sukar untuk dijelaskan dengan jari. Jika terdapat artikel yang baik di wiki, saya akan memberikan pautan kepada mereka, tetapi untuk pemahaman yang lebih baik saya mengesyorkan agar anda Google sendiri. semoga berjaya kepada semua. :) Bagi mereka yang ingin membetulkan terjemahan saya, dan juga bagi mereka yang merasa terlalu lemah untuk membaca dalam bahasa Rusia, anda boleh memuat turun buku asal di sini . Kandungan Bab 1 Helo, Ungkapan Lambda - sedang membaca Bab 2 Menggunakan Koleksi - dalam pembangunan Bab 3 Rentetan, Pembanding dan Penapis - dalam pembangunan Bab 4 Pembangunan dengan Ungkapan Lambda - dalam pembangunan Bab 5 Bekerja dengan Sumber - dalam pembangunan Bab 6 Menjadi Malas - dalam pembangunan Bab 7 Mengoptimumkan sumber - dalam pembangunan Bab 8 Susun atur dengan ungkapan lambda - dalam pembangunan Bab 9 Menggabungkan semuanya - dalam pembangunan

Bab 1 Helo, Ungkapan Lambda!

Kod Java kami sedia untuk transformasi yang luar biasa. Tugasan harian yang kami lakukan menjadi lebih mudah, lebih mudah dan lebih ekspresif. Cara baru pengaturcaraan Java telah digunakan selama beberapa dekad dalam bahasa lain. Dengan perubahan pada Java ini, kita boleh menulis kod yang ringkas, elegan dan ekspresif dengan ralat yang lebih sedikit. Kita boleh menggunakan ini untuk menggunakan piawaian dengan mudah dan melaksanakan corak reka bentuk biasa dengan lebih sedikit baris kod. Dalam buku ini, kami meneroka gaya pengaturcaraan berfungsi menggunakan contoh mudah masalah yang kami lakukan setiap hari. Sebelum kita menyelami gaya elegan ini dan cara baharu membangunkan perisian ini, mari lihat sebab ia lebih baik.
Ubah pemikiran anda
Gaya imperatif ialah apa yang Java berikan kepada kita sejak permulaan bahasa itu. Gaya ini mencadangkan bahawa kami menerangkan kepada Java setiap langkah tentang perkara yang kami mahu bahasa itu lakukan, dan kemudian kami hanya memastikan bahawa langkah tersebut diikuti dengan setia. Ini berfungsi dengan baik, tetapi ia masih tahap rendah. Kod itu akhirnya menjadi terlalu bertele-tele, dan kami sering mahukan bahasa yang lebih pintar sedikit. Kita kemudian boleh mengatakannya secara deklaratif - apa yang kita mahu, dan tidak menyelidiki cara melakukannya. Terima kasih kepada pembangun, Java kini boleh membantu kami melakukan ini. Mari lihat beberapa contoh untuk memahami faedah dan perbezaan antara pendekatan ini.
Cara biasa
Mari kita mulakan dengan asas yang biasa untuk melihat dua paradigma dalam tindakan. Ini menggunakan kaedah penting untuk mencari Chicago dalam koleksi bandar - penyenaraian dalam buku ini hanya menunjukkan coretan kod. boolean found = false; for(String city : cities) { if(city.equals("Chicago")) { found = true; break; } } System.out.println("Found chicago?:" + found); Versi imperatif kod adalah bising (apa kaitan perkataan ini dengannya?) dan tahap rendah, terdapat beberapa bahagian boleh ubah. Mula-mula kita mencipta bendera boolean busuk ini yang dipanggil found dan kemudian kita mengulangi setiap elemen dalam koleksi. Jika kami menemui bandar yang kami cari, kami menetapkan bendera kepada benar dan memecahkan gelung. Akhirnya kami mencetak hasil carian kami ke konsol.
Ada cara yang lebih baik
Sebagai pengaturcara Java yang pemerhati, pandangan seketika pada kod ini boleh mengubahnya menjadi sesuatu yang lebih ekspresif dan lebih mudah dibaca, seperti ini: System.out.println("Found chicago?:" + cities.contains("Chicago")); Berikut ialah contoh gaya perisytiharan - kaedah contains() membantu kita mendapatkan terus apa yang kita perlukan.
Perubahan sebenar
Perubahan ini akan membawa sejumlah peningkatan yang baik kepada kod kami:
  • Tiada kekecohan dengan pembolehubah boleh ubah
  • Lelaran gelung tersembunyi di bawah hud
  • Kurang kekacauan kod
  • Kejelasan kod yang lebih besar, menumpukan perhatian
  • Kurang impedans; kod mengekori niat perniagaan dengan rapat
  • Kurang peluang kesilapan
  • Lebih mudah difahami dan disokong
Di luar kes mudah
Ini adalah contoh mudah fungsi deklaratif yang menyemak kehadiran elemen dalam koleksi; ia telah digunakan untuk masa yang lama di Jawa. Sekarang bayangkan tidak perlu menulis kod penting untuk operasi yang lebih maju seperti menghuraikan fail, bekerja dengan pangkalan data, membuat permintaan untuk perkhidmatan web, mencipta multithreading, dsb. Java kini memungkinkan untuk menulis kod ringkas dan elegan yang menjadikannya lebih sukar untuk membuat kesilapan, bukan sahaja dalam operasi mudah, tetapi sepanjang keseluruhan aplikasi kami.
Cara lama
Mari kita lihat contoh lain. Kami sedang mencipta koleksi dengan harga dan akan mencuba beberapa cara untuk mengira jumlah semua harga diskaun. Katakan kami diminta menjumlahkan semua harga yang nilainya melebihi $20, dengan diskaun 10%. Mula-mula kita lakukan ini dengan cara Java biasa. Kod ini sepatutnya sangat biasa kepada kami: mula-mula kami mencipta pembolehubah boleh ubah totalOfDiscountedPrices di mana kami akan menyimpan nilai yang terhasil. Kami kemudian mengulangi koleksi harga, pilih harga yang melebihi $20, dapatkan harga diskaun dan tambah nilai itu kepada totalOfDiscountedPrices . Pada akhirnya kami memaparkan jumlah semua harga dengan mengambil kira diskaun. Di bawah ialah output kepada konsol final List prices = Arrays.asList( new BigDecimal("10"), new BigDecimal("30"), new BigDecimal("17"), new BigDecimal("20"), new BigDecimal("15"), new BigDecimal("18"), new BigDecimal("45"), new BigDecimal("12")); BigDecimal totalOfDiscountedPrices = BigDecimal.ZERO; for(BigDecimal price : prices) { if(price.compareTo(BigDecimal.valueOf(20)) > 0) totalOfDiscountedPrices = totalOfDiscountedPrices.add(price.multiply(BigDecimal.valueOf(0.9))); } System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);
Jumlah harga diskaun: 67.5
Ia berfungsi, tetapi kod itu kelihatan tidak kemas. Tetapi bukan salah kami, kami menggunakan apa yang ada. Kod ini adalah tahap yang agak rendah - ia mengalami obsesi terhadap primitif (google, perkara yang menarik) dan ia terbang dalam menghadapi prinsip tanggungjawab tunggal . Kita yang bekerja di rumah harus menjauhkan kod tersebut daripada mata kanak-kanak yang bercita-cita menjadi pengaturcara, ia mungkin mencemaskan minda mereka yang rapuh, bersedia untuk soalan "Adakah ini yang perlu anda lakukan untuk terus hidup?"
Ada cara yang lebih baik, satu lagi
Kini kita boleh melakukan yang lebih baik, jauh lebih baik. Kod kami mungkin menyerupai keperluan spesifikasi. Ini akan membantu kami mengurangkan jurang antara keperluan perniagaan dan kod yang melaksanakannya, seterusnya mengurangkan kemungkinan keperluan disalahtafsirkan. Daripada mencipta pembolehubah dan kemudian mengubahnya berulang kali, mari kita bekerja pada tahap abstraksi yang lebih tinggi, seperti dalam penyenaraian berikut. final BigDecimal totalOfDiscountedPrices = prices.stream() .filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0) .map(price -> price.multiply(BigDecimal.valueOf(0.9))) .reduce(BigDecimal.ZERO, BigDecimal::add); System.out.println("Total of discounted prices: " + totalOfDiscountedPrices); Mari baca dengan kuat - penapis harga lebih besar daripada 20, peta (buat pasangan "kunci" "nilai") menggunakan kekunci "harga", harga termasuk diskaun, dan kemudian tambahkannya
- komen penterjemah bermaksud perkataan yang muncul di kepala anda semasa membaca kod .filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
Kod tersebut dilaksanakan bersama dalam urutan logik yang sama seperti yang telah kita baca. Kod itu dipendekkan, tetapi kami menggunakan banyak perkara baharu daripada Java 8. Mula-mula, kami memanggil kaedah stream() pada senarai harga . Ini membuka pintu kepada lelaran tersuai dengan set ciri kemudahan yang kaya yang akan kita bincangkan kemudian. Daripada terus menggelungkan semua nilai dalam senarai harga , kami menggunakan beberapa kaedah khas seperti filter() dan map() . Tidak seperti kaedah yang kami gunakan dalam Java dan JDK, kaedah ini mengambil fungsi tanpa nama - ungkapan lambda - sebagai parameter dalam kurungan. Kami akan mengkajinya dengan lebih terperinci kemudian. Dengan memanggil kaedah reduce() , kami mengira jumlah nilai (harga diskaun) yang diperolehi dalam kaedah map() . Gelung disembunyikan dengan cara yang sama seperti semasa menggunakan kaedah contains() . Kaedah penapis() dan peta() bagaimanapun lebih kompleks. Untuk setiap harga dalam senarai harga , mereka memanggil fungsi lambda yang diluluskan dan menyimpannya ke koleksi baharu. Kaedah reduce() dipanggil pada koleksi ini untuk menghasilkan hasil akhir. Di bawah ialah output kepada konsol
Jumlah harga diskaun: 67.5
Perubahan
Di bawah adalah perubahan berbanding kaedah biasa:
  • Kod itu sedap mata memandang dan tidak bersepah.
  • Tiada operasi peringkat rendah
  • Lebih mudah untuk memperbaiki atau menukar logik
  • Lelaran dikawal oleh perpustakaan kaedah
  • Penilaian gelung yang cekap dan malas
  • Lebih mudah untuk disejajarkan mengikut keperluan
Kami akan membincangkan kemudian bagaimana Java menyediakan penambahbaikan ini.
Lambda untuk menyelamatkan :)
Lambda ialah kunci berfungsi untuk membebaskan kita daripada kerumitan pengaturcaraan yang penting. Dengan mengubah cara kami memprogram, dengan ciri terkini Java, kami boleh menulis kod yang bukan sahaja elegan dan ringkas, tetapi juga kurang terdedah kepada ralat, lebih cekap dan lebih mudah untuk mengoptimumkan, menambah baik dan membuat berbilang benang.
Menang Besar daripada Pengaturcaraan Fungsian
Gaya pengaturcaraan berfungsi mempunyai nisbah isyarat-ke-bunyi yang lebih tinggi ; Kami menulis lebih sedikit baris kod, tetapi setiap baris atau ungkapan melakukan lebih banyak fungsi. Kami mendapat sedikit daripada versi fungsi kod berbanding dengan imperatif:
  • Kami mengelakkan perubahan yang tidak diingini atau penugasan semula pembolehubah, yang merupakan punca ralat dan menyukarkan untuk memproses kod daripada urutan yang berbeza pada masa yang sama. Dalam versi imperatif, kami menetapkan nilai yang berbeza untuk pembolehubah totalOfDiscountedPrices sepanjang gelung . Dalam versi berfungsi, tiada perubahan eksplisit dalam pembolehubah dalam kod. Lebih sedikit perubahan membawa kepada lebih sedikit pepijat dalam kod.
  • Versi fungsi kod lebih mudah untuk disejajarkan. Walaupun pengiraan dalam kaedah map() adalah panjang, kita boleh menjalankannya secara selari tanpa rasa takut apa-apa. Jika kami mengakses kod gaya imperatif daripada urutan yang berbeza, kami perlu bimbang tentang menukar pembolehubah totalOfDiscountedPrices pada masa yang sama . Dalam versi berfungsi, kami mengakses pembolehubah hanya selepas semua perubahan dibuat, ini membebaskan kami daripada bimbang tentang keselamatan benang kod.
  • Kod itu lebih ekspresif. Daripada melaksanakan kod dalam beberapa langkah - mencipta dan memulakan pembolehubah dengan nilai tiruan, menggelung senarai harga, menambah harga diskaun pada pembolehubah dan sebagainya - kami hanya meminta kaedah map() senarai untuk mengembalikan senarai lain harga diskaun dan tambahkannya .
  • Gaya berfungsi lebih ringkas: lebih sedikit baris kod diperlukan daripada versi imperatif. Kod yang lebih padat bermakna kurang menulis, kurang membaca dan lebih mudah diselenggara.
  • Versi fungsi kod adalah intuitif dan mudah difahami, setelah anda mengetahui sintaksnya. Kaedah map() menggunakan fungsi yang diluluskan (yang mengira harga diskaun) untuk setiap elemen koleksi dan menghasilkan koleksi dengan hasilnya, seperti yang dapat kita lihat dalam imej di bawah.

Gambar Rajah 1 - kaedah peta menggunakan fungsi yang diluluskan untuk setiap elemen koleksi
Dengan sokongan ungkapan lambda, kami boleh memanfaatkan sepenuhnya kuasa gaya pengaturcaraan berfungsi di Jawa. Jika kita menguasai gaya ini, kita boleh mencipta kod yang lebih ekspresif, lebih ringkas dengan lebih sedikit perubahan dan ralat. Sebelum ini, salah satu kelebihan utama Java ialah sokongannya untuk paradigma berorientasikan objek. Dan gaya berfungsi tidak bercanggah dengan OOP. Kecemerlangan sebenar dalam beralih daripada pengaturcaraan imperatif kepada deklaratif. Dengan Java 8 kita boleh menggabungkan pengaturcaraan berfungsi dengan gaya berorientasikan objek dengan agak berkesan. Kita boleh terus menggunakan gaya OO pada objek, skop, keadaan dan perhubungannya. Di samping itu, kita boleh memodelkan tingkah laku dan keadaan perubahan, proses perniagaan dan pemprosesan data sebagai satu siri set fungsi.
Mengapa kod dalam gaya berfungsi?
Kami telah melihat faedah keseluruhan gaya pengaturcaraan berfungsi, tetapi adakah gaya baharu ini patut dipelajari? Adakah ini satu perubahan kecil dalam bahasa atau adakah ia akan mengubah hidup kita? Kita mesti mendapatkan jawapan kepada soalan-soalan ini sebelum kita membuang masa dan tenaga kita. Menulis kod Java tidak begitu sukar; sintaks bahasanya mudah. Kami selesa dengan perpustakaan dan API biasa. Apa yang benar-benar memerlukan kami untuk berusaha untuk menulis dan mengekalkan kod adalah aplikasi Enterprise biasa yang kami gunakan Java untuk pembangunan. Kita perlu memastikan bahawa rakan pengaturcara menutup sambungan ke pangkalan data pada masa yang betul, bahawa mereka tidak memegangnya atau melakukan transaksi lebih lama daripada yang diperlukan, bahawa mereka menangkap pengecualian sepenuhnya dan pada tahap yang betul, bahawa mereka menggunakan dan melepaskan kunci dengan betul. ... helaian ini boleh diteruskan untuk masa yang sangat lama. Setiap hujah di atas sahaja tidak mempunyai berat, tetapi bersama-sama, apabila digabungkan dengan kerumitan pelaksanaan yang wujud, ia menjadi luar biasa, memakan masa dan sukar untuk dilaksanakan. Bagaimana jika kita boleh merangkum kerumitan ini menjadi kepingan kecil kod yang juga boleh mengurusnya dengan baik? Kemudian kita tidak akan sentiasa menghabiskan tenaga untuk melaksanakan piawaian. Ini akan memberikan kelebihan yang serius, jadi mari kita lihat bagaimana gaya berfungsi boleh membantu.
Joe bertanya
Adakah kod pendek* bermaksud lebih sedikit huruf kod?
* kita bercakap tentang perkataan ringkas , yang mencirikan gaya fungsi kod menggunakan ungkapan lambda
Dalam konteks ini, kod itu dimaksudkan untuk ringkas, tanpa tambahan, dan dikurangkan kepada kesan langsung untuk menyampaikan niat dengan lebih berkesan. Ini adalah faedah yang meluas. Menulis kod adalah seperti menyusun bahan-bahan: menjadikannya ringkas seperti menambah sos padanya. Kadangkala ia memerlukan lebih banyak usaha untuk menulis kod tersebut. Kurang kod untuk dibaca, tetapi ia menjadikan kod lebih telus. Adalah penting untuk memastikan kod itu jelas apabila memendekkannya. Kod ringkas adalah serupa dengan helah reka bentuk. Kod ini memerlukan kurang menari dengan tamborin. Ini bermakna kita boleh melaksanakan idea kita dengan cepat dan meneruskan jika ia berfungsi dan meninggalkannya jika ia tidak memenuhi jangkaan.
Lelaran pada steroid
Kami menggunakan iterator untuk memproses senarai objek, serta berfungsi dengan Set dan Peta. Iterator yang kami gunakan dalam Java sudah biasa kepada kami; walaupun mereka primitif, mereka tidak mudah. Bukan sahaja mereka mengambil beberapa baris kod, mereka juga agak sukar untuk ditulis. Bagaimanakah kita mengulangi semua elemen koleksi? Kita boleh menggunakan gelung untuk. Bagaimanakah kita memilih beberapa elemen daripada koleksi? Menggunakan yang sama untuk gelung, tetapi menggunakan beberapa pembolehubah boleh ubah tambahan yang perlu dibandingkan dengan sesuatu daripada koleksi. Kemudian, selepas memilih nilai tertentu, bagaimanakah kita melaksanakan operasi pada satu nilai, seperti minimum, maksimum atau beberapa nilai purata? Sekali lagi kitaran, sekali lagi pembolehubah baru. Ini mengingatkan peribahasa, anda tidak dapat melihat pokok kerana hutan (yang asal menggunakan permainan kata-kata yang berkaitan dengan lelaran dan bermaksud "Semuanya diambil, tetapi tidak semuanya berjaya" - nota penterjemah). jdk kini menyediakan iterator dalaman untuk pelbagai kenyataan: satu untuk memudahkan gelung, satu untuk mengikat kebergantungan hasil yang diperlukan, satu untuk menapis nilai output, satu untuk mengembalikan nilai, dan beberapa fungsi kemudahan untuk mendapatkan min, maks, purata, dsb. Di samping itu, kefungsian operasi ini boleh digabungkan dengan sangat mudah, supaya kami boleh menggabungkan set berbeza daripadanya untuk melaksanakan logik perniagaan dengan lebih mudah dan kod yang lebih sedikit. Apabila kita selesai, kod akan lebih mudah difahami kerana ia mencipta penyelesaian logik dalam urutan yang diperlukan oleh masalah. Kita akan melihat beberapa contoh kod sedemikian dalam Bab 2 dan kemudian dalam buku ini.
Aplikasi algoritma
Algoritma memacu aplikasi perusahaan. Sebagai contoh, kita perlu menyediakan operasi yang memerlukan semakan kuasa. Kami perlu memastikan bahawa urus niaga selesai dengan cepat dan semakan diselesaikan dengan betul. Tugasan sedemikian sering dikurangkan kepada kaedah yang sangat biasa, seperti dalam penyenaraian di bawah: Transaction transaction = getFromTransactionFactory(); //... Операция выполняющаяся во время транзакции... checkProgressAndCommitOrRollbackTransaction(); UpdateAuditTrail(); Terdapat dua masalah dengan pendekatan ini. Pertama, ini sering membawa kepada penggandaan usaha pembangunan, yang seterusnya membawa kepada peningkatan dalam kos penyelenggaraan aplikasi. Kedua, adalah sangat mudah untuk terlepas pengecualian yang mungkin dilemparkan dalam kod aplikasi ini, sekali gus menjejaskan pelaksanaan transaksi dan laluan cek. Kita boleh menggunakan blok cuba-akhir yang betul, tetapi setiap kali seseorang menyentuh kod ini, kita perlu menyemak semula bahawa logik kod itu tidak rosak. Jika tidak, kami boleh meninggalkan kilang dan menghidupkan keseluruhan kod itu. Daripada menerima transaksi, kami boleh menghantar kod pemprosesan kepada fungsi yang diurus dengan baik, seperti kod di bawah. runWithinTransaction((Transaction transaction) -> { //... Операция выполняющаяся во время транзакции... }); Perubahan kecil ini menambahkan penjimatan yang besar. Algoritma untuk semakan status dan semakan aplikasi diberikan tahap abstraksi baharu dan dikapsulkan menggunakan kaedah runWithinTransaction() . Dalam kaedah ini kami meletakkan sekeping kod yang harus dilaksanakan dalam konteks transaksi. Kami tidak perlu lagi bimbang tentang terlupa melakukan sesuatu atau sama ada kami mendapat pengecualian di tempat yang betul. Fungsi algoritma mengurus perkara ini. Isu ini akan dibincangkan dengan lebih terperinci dalam Bab 5.
Sambungan Algoritma
Algoritma semakin kerap digunakan, tetapi agar ia dapat digunakan sepenuhnya dalam pembangunan aplikasi perusahaan, cara untuk melanjutkannya diperlukan.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION