Mengapa Java 8's Optional tidak digunakan dalam argumen

392

Saya telah membaca di banyak situs Web. Opsional hanya boleh digunakan sebagai jenis pengembalian, dan tidak digunakan dalam argumen metode. Saya berjuang untuk menemukan alasan logis mengapa. Misalnya saya punya sepotong logika yang memiliki 2 parameter opsional. Karena itu saya pikir akan masuk akal untuk menulis tanda tangan metode saya seperti ini (solusi 1):

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}

Banyak halaman web yang menentukan Opsional tidak boleh digunakan sebagai argumen metode. Dengan mengingat hal ini, saya dapat menggunakan metode tanda tangan berikut dan menambahkan komentar Javadoc yang jelas untuk menentukan bahwa argumen mungkin nol, berharap pengelola masa depan akan membaca Javadoc dan karena itu selalu melakukan pemeriksaan nol sebelum menggunakan argumen (solusi 2) :

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Atau saya bisa mengganti metode saya dengan empat metode publik untuk menyediakan antarmuka yang lebih bagus dan membuatnya lebih jelas p1 dan p2 adalah opsional (solusi 3):

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Sekarang saya mencoba menulis kode kelas yang menggunakan potongan logika ini untuk setiap pendekatan. Saya pertama-tama mengambil dua parameter input dari objek lain yang mengembalikan Optionals dan kemudian, saya memohon calculateSomething. Oleh karena itu, jika solusi 1 digunakan, kode panggilan akan terlihat seperti ini:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

jika solusi 2 digunakan, kode panggilan akan terlihat seperti ini:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

jika solusi 3 diterapkan, saya bisa menggunakan kode di atas atau saya bisa menggunakan yang berikut (tapi kode ini jauh lebih banyak):

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

Jadi pertanyaan saya adalah: Mengapa dianggap praktik yang buruk untuk menggunakan Optionals sebagai argumen metode (lihat solusi 1)? Sepertinya solusi yang paling mudah dibaca bagi saya dan membuatnya paling jelas bahwa parameter bisa kosong / nol untuk pengelola masa depan. (Saya sadar bahwa perancang yang Optionaldimaksudkan hanya digunakan sebagai tipe pengembalian, tetapi saya tidak dapat menemukan alasan logis untuk tidak menggunakannya dalam skenario ini).

Neil Stevens
sumber
16
Jika Anda menggunakan opsional, tidakkah Anda harus memeriksa bahwa opsional tidak lulus sebagai parameter null?
biziclop
17
Ya, tetapi akan membuatnya jelas bagi orang lain yang menjaga kode di masa depan bahwa parameternya bisa kosong / null, karena itu berpotensi menghindari pengecualian penunjuk nol di masa depan
Neil Stevens
1
Wow. Argumen kosong diteruskan ke metode? Itu sangat Visual Basic. Prinsip apa yang dilanggar? SRP (mungkin). Hal ini juga melanggar prinsip lain yang namanya membuat saya kehilangan jalur informasi yang diperlukan HANYA untuk metode atau fungsi untuk melakukan tugasnya.
Luminous
20
Segala sesuatu yang secara teori mungkin nol adalah seperti setiap metode di perpustakaan yang mungkin memanggil System.exit (0). Anda tidak dapat memeriksa terhadap ini dan Anda tidak harus memeriksa terhadap ini. Segala sesuatu yang harus Anda lakukan sepanjang waktu yang seharusnya (hampir) tidak pernah Anda lakukan. Seperti membuat semua parameter final. Biarkan alat Anda membantu Anda mencegah perubahan nilai parameter atau lupa untuk menginisialisasi bidang alih-alih membuat kode Anda tidak dapat dibaca oleh ribuan final dan sebanyak nol pemeriksaan.
yeoman
6
Sebenarnya cukup gunakan anotasi NonNull / Nullable, itulah yang Anda cari dalam situasi ini, bukan opsional.
Bill K

Jawaban:

202

Oh, gaya pengkodean itu harus diambil dengan sedikit garam.

  1. (+) Melewati hasil opsional ke metode lain, tanpa analisis semantik; meninggalkan itu ke metode, cukup baik-baik saja.
  2. (-) Menggunakan parameter opsional yang menyebabkan logika kondisional di dalam metode secara harfiah kontra-produktif.
  3. (-) Perlu mengepak argumen dalam Opsional, tidak optimal untuk kompiler, dan melakukan pembungkus yang tidak perlu.
  4. (-) Dibandingkan dengan parameter nullable, Opsional lebih mahal.

Secara umum: Opsional menyatukan dua negara, yang harus diurai. Oleh karena itu lebih cocok untuk hasil daripada input, untuk kompleksitas aliran data.

Joop Eggen
sumber
38
Sebenarnya, memiliki Optionalparameter mewakili salah satu dari tiga status: a nullOpsional, non-null Optionalwith, isPresent() == falsedan non-null, Optionalmembungkus nilai aktual.
biziclop
16
@biziclop ya, poin yang tidak dapat dihindari sudah dikritik. Tetapi tujuannya adalah untuk memiliki ekspresi bukan nol saja. Itu tidak butuh waktu lama, untuk mendengar saran untuk menghindari Opsional dalam beberapa kasus juga, cukup ironis. A @NotNull Optional.
Joop Eggen
80
@biziclop Perhatikan bahwa jika Anda menggunakan Optionalsama sekali, maka nyatakan 1 ( nullOpsional) biasanya menunjukkan kesalahan pemrograman, jadi Anda mungkin juga tidak menanganinya (biarkan saja NullPointerException)
user253751
50
"suboptimal for the compiler", "Dibandingkan dengan parameter nullable, Opsional lebih mahal" - argumen ini bisa valid untuk bahasa C dan bukan untuk bahasa Java. Pemrogram Java harus fokus pada kode bersih, portabilitas, testabilitas, arsitektur yang baik, modularitas, dll, dan bukan pada "Opsional lebih mahal daripada referensi nol". Dan jika Anda menemukan bahwa Anda perlu fokus pada optimasi mikro, maka Anda sebaiknya melewatkan Objek, Daftar, Generik dan beralih ke array dan primitif (Saya tidak ingin menyinggung di sini, saya hanya berbagi pendapat saya) .
Kacper86
15
"suboptimal for the compiler": Optimalisasi prematur adalah akar dari semua kejahatan ... jika Anda tidak menulis kode kinerja kritis (yang sering terjadi ketika mencoba menentukan antarmuka yang bersih), ini seharusnya tidak menjadi perhatian.
Mohan
165

The posting terbaik yang pernah kulihat pada topik ditulis oleh Daniel Olszewski :

Meskipun mungkin tergoda untuk mempertimbangkan Opsional untuk parameter metode yang tidak wajib, solusi seperti itu pucat dibandingkan dengan alternatif lain yang mungkin. Untuk mengilustrasikan masalah, periksa deklarasi konstruktor berikut:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

Sepintas mungkin terlihat sebagai keputusan desain yang tepat. Bagaimanapun, kami secara eksplisit menandai parameter lampiran sebagai opsional. Namun, untuk memanggil konstruktor, kode klien dapat menjadi sedikit canggung.

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Alih-alih memberikan kejelasan, metode pabrik dari kelas Opsional hanya mengganggu pembaca. Perhatikan hanya ada satu parameter opsional, tetapi bayangkan memiliki dua atau tiga. Paman Bob pasti tidak akan bangga dengan kode semacam itu 😉

Ketika suatu metode dapat menerima parameter opsional, lebih baik untuk mengadopsi pendekatan yang telah terbukti dan merancang kasus seperti itu menggunakan metode overloading. Dalam contoh kelas SystemMessage, mendeklarasikan dua konstruktor terpisah lebih unggul daripada menggunakan Opsional.

public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}

Perubahan itu membuat kode klien lebih sederhana dan lebih mudah dibaca.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
Gili
sumber
10
Itu banyak copy + paste ketika hanya satu atau dua paragraf yang relevan.
Garret Wilson
47
Sayangnya penjelasan ini tidak membahas masalah ketika pemanggil mis. Mengurai beberapa informasi mungkin opsional. Dengan metode overloading (seperti yang disarankan di atas), kode panggilan harus mengatakan, "Apakah X ada? Jika demikian, saya akan memanggil metode kelebihan beban A. Apakah Y ada? Saya harus memanggil metode kelebihan beban B. Jika X dan Y hadir, saya harus memanggil metode C. kelebihan beban " Dan seterusnya. Mungkin ada jawaban yang bagus untuk ini, tetapi penjelasan tentang "mengapa" ini tidak membahasnya.
Garret Wilson
9
Juga, ketika datang ke koleksi, ada perbedaan yang jelas antara koleksi kosong dan tidak ada koleksi. Misalnya, cache. Apakah ini cache miss? kosong opsional / nol. Apakah ada hit cache yang kebetulan merupakan koleksi kosong? opsional penuh / koleksi.
Ajax
1
@Ajax Saya pikir Anda salah paham artikel. Mereka mengutip poin yang dianjurkan oleh buku Java Efektif , yang mengatakan bahwa ketika metode pengembalian tipe adalah Koleksi (bukan objek yang sewenang-wenang sebagai cache akan kembali) maka Anda harus memilih mengembalikan koleksi kosong daripada nullatau Optional.
Gili
4
Tentu, Anda harus mendukungnya , tetapi Anda tidak selalu memiliki kontrol atas beberapa kode, dan, dalam arti yang sangat nyata, Anda mungkin ingin membedakan antara "ada nilai dan itu adalah koleksi kosong" versus "tidak ada nilai didefinisikan (belum) ". Karena "magic null" juga merupakan praktik yang tidak disarankan, terserah Anda, pengembang, untuk memilih opsi yang paling tidak buruk. Saya lebih suka opsional kosong untuk mewakili cache miss bukan koleksi kosong, karena nilai cache sebenarnya mungkin menjadi koleksi kosong.
Ajax
86

Hampir tidak ada alasan bagus untuk tidak menggunakan Optionalparameter. Argumen melawan ini bergantung pada argumen dari otoritas (lihat Brian Goetz - argumennya adalah kita tidak dapat menegakkan opsional bukan nol) atau bahwa Optionalargumen mungkin nol (pada dasarnya argumen yang sama). Tentu saja, setiap referensi di Java bisa nol, kita perlu mendorong aturan yang diberlakukan oleh kompiler, bukan memori pemrogram (yang bermasalah dan tidak skala).

Bahasa pemrograman fungsional mendorong Optionalparameter. Salah satu cara terbaik untuk menggunakan ini adalah memiliki beberapa parameter opsional dan menggunakan liftM2menggunakan fungsi dengan asumsi parameter tidak kosong dan mengembalikan opsional (lihat http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data / Option.html # liftM2-fj.F- ). Java 8 sayangnya telah mengimplementasikan perpustakaan yang sangat terbatas yang mendukung opsional.

Sebagai pemrogram Java, kita hanya boleh menggunakan null untuk berinteraksi dengan pustaka lawas.

Mark Perry
sumber
3
Bagaimana kalau menggunakan @Nonnulldan @Nullabledari javax.annotation saja? Saya menggunakannya secara luas di perpustakaan yang saya kembangkan, dan dukungan yang diberikan oleh IDE (IntelliJ) sangat bagus.
Rogério
1
Itu bagus, tetapi Anda harus menggunakan anotasi ini di mana-mana dan Anda memerlukan perpustakaan untuk mendukung metode seperti peta, flatMap / bind, liftM2, urutan, dll.
Mark Perry
14
Bahasa pemrograman fungsional mendorong parameter opsional. Kutipan diperlukan. Sebagian besar fungsi seharusnya tidak mengambil opsional; alih-alih, tanggung jawab untuk berurusan (menggunakan fungsi tingkat tinggi yang sesuai) dengan ada atau tidak adanya nilai ada pada penelepon fungsi tersebut.
jub0bs
5
Ini. Memang, tidak ada jawaban yang cukup meyakinkan, dan tidak satu pun dari mereka menjawab pertanyaan khusus ini "mengapa menggunakan opsional sebagai parameter metode dianggap praktik buruk sementara menjelaskan metode parameter dengan @NonNullbenar-benar baik jika mereka melayani tujuan yang sama dengan cara yang berbeda?" Bagi saya, hanya ada satu argumen yang setidaknya masuk akal: "Opsional harus digunakan untuk menyediakan API yang lebih baik yang memiliki tipe pengembalian yang jelas. Namun untuk argumen metode, fungsi kelebihan beban dapat digunakan." - masih, saya tidak berpikir ini adalah argumen yang cukup kuat.
Utku Özdemir
1
Tentu saja, preferrable to null, tetapi apa yang lebih preferrable adalah tidak memerlukan banyak nilai opsional karena desain yang bagus: D
yeoman
12

Nasihat ini merupakan varian dari aturan "sedapat mungkin tidak spesifik mengenai input dan sespesifik mungkin mengenai output".

Biasanya jika Anda memiliki metode yang mengambil nilai bukan nol, Anda dapat memetakannya di atas Optional, sehingga versi polos lebih spesifik untuk input. Namun ada beberapa alasan yang mungkin mengapa Anda ingin meminta Optionalargumen:

  • Anda ingin fungsi Anda digunakan bersama dengan API lain yang mengembalikan sebuah Optional
  • Fungsi Anda harus mengembalikan sesuatu selain yang kosong Optionaljika nilai yang diberikan kosong
  • Anda pikir Optionalsangat mengagumkan sehingga siapa pun yang menggunakan API Anda harus diminta untuk mempelajarinya ;-)
llogiq
sumber
10

Pola dengan Optionaladalah untuk seseorang agar tidak kembali null . Masih sangat mungkin nulluntuk menggunakan metode.

Meskipun ini belum benar-benar resmi, Anda dapat menggunakan anotasi gaya JSR-308 untuk menunjukkan apakah Anda menerima nullnilai atau tidak ke dalam fungsi. Perhatikan bahwa Anda harus memiliki alat yang tepat untuk benar-benar mengidentifikasi itu, dan itu akan memberikan lebih banyak pemeriksaan statis daripada kebijakan runtime yang dapat ditegakkan, tetapi itu akan membantu.

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}
Makoto
sumber
Masalahnya di sini adalah bahwa @NotNull bukan kasus default dan harus dijelaskan secara eksplisit - maka boilerplate dan hal-hal yang orang tidak akan lakukan karena kemalasan.
dwegener
1
@denerator Ya, tapi Optionaljuga tidak memperbaiki masalah, maka saran saya untuk anotasi.
Makoto
2
Jauh lebih sulit untuk mengabaikan Opsional daripada mengabaikan anotasi yang hanya akan Anda perhatikan jika membaca dokumen / sumber atau jika alat Anda dapat menangkapnya (analisis statis tidak selalu dapat menentukan nullability dengan benar).
Ajax
Perhatikan bahwa @Nullable tidak berarti Anda "menerima" null sebagai nilai yang valid, yaitu tidak membuang pengecualian apa pun. Ini mungkin hanya berarti bahwa Anda berjaga-jaga terhadap kasus ini, tetapi masih akan melemparkan pengecualian (Ini adalah semantik Findbugs). Jadi, Anda dapat memperkenalkan ambiguitas dengan anotasi semacam itu alih-alih kejelasan.
tkruse
Saya tidak yakin ambiguitas apa yang ada di @ user2986984. "Not handling null" hanya bisa secara realistis berarti pengecualian dilemparkan.
Makoto
7

Ini agak konyol bagi saya, tetapi satu-satunya alasan yang dapat saya pikirkan adalah bahwa argumen objek dalam parameter metode sudah opsional dengan cara - mereka bisa menjadi nol. Oleh karena itu memaksa seseorang untuk mengambil objek yang sudah ada dan membungkusnya dalam opsional adalah hal yang tidak ada gunanya.

Yang sedang berkata, metode chaining bersama yang mengambil / mengembalikan opsional adalah hal yang wajar untuk dilakukan, misalnya Mungkin monad.

Steve B.
sumber
7
Tidak dapat mengembalikan nilai dan bidang menjadi nol juga? Jadi Optionaltidak ada gunanya sama sekali?
Samuel Edwin Ward
6

Lihat JavaDoc di JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html , sebuah catatan API ditambahkan:

Catatan API: Opsional terutama ditujukan untuk digunakan sebagai tipe metode pengembalian di mana ada kebutuhan yang jelas untuk mewakili "tidak ada hasil," dan di mana menggunakan null kemungkinan menyebabkan kesalahan.

Xiaolong
sumber
4

Menurut saya, Opsional harus Monad dan ini tidak mungkin di Jawa.

Dalam pemrograman fungsional, Anda berurusan dengan fungsi pesanan murni dan lebih tinggi yang mengambil dan menyusun argumen mereka hanya berdasarkan "tipe domain bisnis" mereka. Menyusun fungsi yang menjadi sumber makanan, atau yang perhitungannya harus dilaporkan, dunia nyata (disebut efek samping) memerlukan penerapan fungsi yang secara otomatis membongkar nilai-nilai dari monad yang mewakili dunia luar (Negara, Konfigurasi, Berjangka, Mungkin, Entah, Penulis, dll ...); ini disebut mengangkat. Anda dapat menganggapnya sebagai semacam pemisahan keprihatinan.

Mencampur dua level abstraksi ini tidak memudahkan keterbacaan sehingga Anda lebih baik menghindarinya.

Eddy
sumber
3

Alasan lain untuk berhati-hati ketika memberikan Optionalparameter sebagai adalah bahwa suatu metode harus melakukan satu hal ... Jika Anda lulus suatu Optionalparam, Anda dapat melakukan lebih dari satu hal, mungkin sama dengan melewatkan param boolean.

public void method(Optional<MyClass> param) {
     if(param.isPresent()) {
         //do something
     } else {
         //do some other
     }
 }
Pau
sumber
Saya pikir itu bukan alasan yang bagus. Logika yang sama dapat diterapkan untuk memeriksa apakah param adalah null ketika tidak opsional digunakan. Sebenarnya, if(param.isPresent())ini bukan pendekatan terbaik untuk menggunakan Opsional, sebagai gantinya Anda dapat menggunakan:param.forEach(() -> {...})
hdkrus
Saya juga tidak menyukai gagasan untuk melewati parabel yang dapat dibatalkan. Ngomong-ngomong, saya bilang Anda bisa mendukung, tentu saja ada pengecualian Anda dapat menggunakannya, terserah Anda, gunakan saja dengan hati-hati, itu saja. Tidak ada aturan yang berlaku untuk semua skenario.
Pau
2

Menerima Opsional sebagai parameter menyebabkan pembungkus yang tidak perlu pada tingkat pemanggil.

Misalnya dalam hal:

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}

Misalkan Anda memiliki dua string bukan-nol (mis. Dikembalikan dari beberapa metode lain):

String p1 = "p1"; 
String p2 = "p2";

Anda terpaksa membungkusnya dalam Opsional meskipun Anda tahu itu bukan Kosong.

Ini menjadi lebih buruk ketika Anda harus menulis dengan struktur "yang dapat dipetakan" lainnya, yaitu. Eithers :

Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a 
  string >));

ref:

Metode seharusnya tidak mengharapkan Opsi sebagai parameter, ini hampir selalu merupakan bau kode yang mengindikasikan kebocoran aliran kontrol dari penelepon ke callee, itu harus menjadi tanggung jawab penelepon untuk memeriksa konten Opsi.

ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749

gpilotino
sumber
1

Saya pikir itu karena Anda biasanya menulis fungsi Anda untuk memanipulasi data, dan kemudian mengangkatnya untuk Optionalmenggunakan mapdan fungsi yang serupa. Ini menambahkan Optionalperilaku default untuk itu. Tentu saja, mungkin ada kasus, ketika perlu untuk menulis fungsi bantu Anda sendiri yang berfungsi Optional.

Danil Gaponov
sumber
1

Saya percaya resonansi makhluk adalah Anda harus terlebih dahulu memeriksa apakah Opsional itu nol atau tidak dan kemudian mencoba mengevaluasi nilai yang dibungkusnya. Terlalu banyak validasi yang tidak perlu.

Macchiatow
sumber
2
Melewati null Opsional referensi dapat dianggap sebagai kesalahan pemrograman (karena Opsional menyediakan cara eksplisit melewati nilai "kosong"), jadi tidak ada gunanya memeriksa, kecuali Anda ingin menghindari melemparkan pengecualian dalam semua kasus.
pvgoran
1

Opsional tidak dirancang untuk tujuan ini, seperti dijelaskan dengan baik oleh Brian Goetz .

Anda selalu dapat menggunakan @Nullable untuk menyatakan bahwa argumen metode bisa nol. Menggunakan opsional tidak benar-benar memungkinkan Anda untuk menulis logika metode Anda dengan lebih rapi.

Kieran
sumber
5
Maaf, tapi saya tidak bisa setuju dengan argumen "tidak dirancang" atau "seseorang merekomendasikannya". Seorang insinyur kita harus spesifik. Menggunakan @Nullable jauh lebih buruk daripada menggunakan Opsional, karena Opsional jauh lebih verbose dari sudut pandang API. Saya tidak melihat alasan bagus untuk tidak menggunakan Opsional sebagai argumen (asalkan Anda tidak ingin menggunakan metode overloading)
Kacper86
0

Satu lagi pendekatan, yang bisa Anda lakukan adalah

// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}

Setelah Anda membangun suatu fungsi (pemasok dalam kasus ini), Anda akan dapat meneruskan ini sebagai variabel lain dan akan dapat memanggilnya menggunakan

calculatedValueSupplier.apply();

Idenya di sini adalah apakah Anda sudah mendapat nilai opsional atau tidak akan menjadi detail internal fungsi Anda dan tidak akan di parameter. Memikirkan fungsi ketika memikirkan opsional sebagai parameter sebenarnya adalah teknik yang sangat berguna yang saya temukan.

Mengenai pertanyaan Anda apakah Anda benar-benar harus melakukannya atau tidak didasarkan pada preferensi Anda, tetapi seperti kata orang lain itu membuat API Anda jelek untuk sedikitnya.

Swaraj Yadav
sumber
0

Pada awalnya, saya juga lebih suka untuk melewatkan Opsional sebagai parameter, tetapi jika Anda beralih dari perspektif API-Desainer ke perspektif API-Pengguna, Anda melihat kerugiannya.

Sebagai contoh Anda, di mana setiap parameter adalah opsional, saya akan menyarankan untuk mengubah metode perhitungan ke kelas sendiri seperti berikut:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();
Torsten
sumber
0

Saya tahu bahwa pertanyaan ini lebih tentang pendapat daripada fakta keras. Tapi saya baru saja pindah dari menjadi pengembang .net ke yang java, jadi saya baru saja bergabung dengan pihak Opsional. Juga, saya lebih suka menyatakan ini sebagai komentar, tetapi karena tingkat poin saya tidak memungkinkan saya untuk berkomentar, saya terpaksa menempatkan ini sebagai jawaban.

Apa yang telah saya lakukan, yang telah membantu saya dengan baik. Apakah menggunakan Opsional untuk jenis kembali, dan hanya menggunakan Opsional sebagai parameter, jika saya memerlukan nilai Opsional, dan cuaca atau Opsional memiliki nilai dalam metode.

Jika saya hanya peduli tentang nilai, saya memeriksa isPresent sebelum memanggil metode, jika saya memiliki semacam logging atau logika yang berbeda dalam metode yang tergantung pada jika nilai ada, maka saya akan dengan senang hati meneruskan dalam Opsional.

Blair
sumber
0

Ini karena kami memiliki persyaratan berbeda untuk pengguna API dan pengembang API.

Pengembang bertanggung jawab untuk menyediakan spesifikasi yang tepat dan implementasi yang benar. Oleh karena itu, jika pengembang sudah mengetahui bahwa suatu argumen adalah opsional, implementasi harus menanganinya dengan benar, apakah itu nol atau opsional. API harus sesederhana mungkin bagi pengguna, dan null adalah yang paling sederhana.

Di sisi lain, hasilnya diteruskan dari pengembang API ke pengguna. Namun spesifikasinya lengkap dan bertele-tele, masih ada kemungkinan pengguna tidak menyadarinya atau hanya malas untuk menghadapinya. Dalam hal ini, hasil Opsional memaksa pengguna untuk menulis beberapa kode tambahan untuk menangani kemungkinan hasil kosong.

speedogoo
sumber
0

Pertama-tama, jika Anda menggunakan metode 3, Anda dapat mengganti 14 baris kode terakhir dengan ini:

int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

Empat variasi yang Anda tulis adalah metode kenyamanan . Anda hanya harus menggunakannya ketika mereka lebih nyaman. Itu juga pendekatan terbaik. Dengan begitu, API sangat jelas anggota mana yang perlu dan mana yang tidak. Jika Anda tidak ingin menulis empat metode, Anda dapat mengklarifikasi hal-hal dengan cara Anda memberi nama parameter Anda:

public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)

Dengan cara ini, jelas bahwa nilai nol diizinkan.

Penggunaan Anda p1.orElse(null)menggambarkan bagaimana verbose kode kami dapatkan ketika menggunakan Opsional, yang merupakan bagian dari alasan saya menghindarinya. Opsional ditulis untuk pemrograman fungsional. Streaming membutuhkannya. Metode Anda mungkin tidak boleh mengembalikan Opsional kecuali jika perlu menggunakannya dalam pemrograman fungsional. Ada metode, seperti Optional.flatMap()metode, yang memerlukan referensi ke fungsi yang mengembalikan Opsional. Ini tanda tangannya:

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

Jadi itu biasanya satu-satunya alasan bagus untuk menulis metode yang mengembalikan Opsional. Tetapi bahkan di sana, itu bisa dihindari. Anda dapat meneruskan pengambil yang tidak mengembalikan Opsional ke metode seperti flatMap (), dengan membungkusnya dengan metode lain yang mengubah fungsi menjadi tipe yang tepat. Metode pembungkus terlihat seperti ini:

public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
    return t -> Optional.ofNullable(function.apply(t));
}

Jadi anggaplah Anda memiliki seorang pengambil seperti ini: String getName()

Anda tidak dapat meneruskannya ke flatMap seperti ini:

opt.flatMap(Widget::getName) // Won't work!

Tapi Anda bisa melewatinya seperti ini:

opt.flatMap(optFun(Widget::getName)) // Works great!

Di luar pemrograman fungsional, Opsional harus dihindari.

Brian Goetz mengatakan yang terbaik ketika mengatakan ini:

Alasan Opsional ditambahkan ke Java adalah karena ini:

return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .findFirst()
    .getOrThrow(() -> new InternalError(...));

lebih bersih dari ini:

Method matching =
    Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .getFirst();
if (matching == null)
  throw new InternalError("Enclosing method not found");
return matching;
MiguelMunoz
sumber
1
Nah, itulah SALAH SATU alasan mengapa ditambahkan ke Jawa. Ada banyak yang lain. Mengganti rantai panjang pernyataan 'jika' bersarang yang melintasi ke struktur data dengan urutan tunggal panggilan berantai ke Optional.map adalah favorit pribadi saya. Dunia pemrograman Fungsional Bahasa memiliki banyak kegunaan yang menarik untuk Opsional selain hanya mengganti cek nol seperti ini.
Some Guy