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 Optional
s 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 Optional
s 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 Optional
dimaksudkan hanya digunakan sebagai tipe pengembalian, tetapi saya tidak dapat menemukan alasan logis untuk tidak menggunakannya dalam skenario ini).
null
?Jawaban:
Oh, gaya pengkodean itu harus diambil dengan sedikit garam.
Secara umum: Opsional menyatukan dua negara, yang harus diurai. Oleh karena itu lebih cocok untuk hasil daripada input, untuk kompleksitas aliran data.
sumber
Optional
parameter mewakili salah satu dari tiga status: anull
Opsional, non-nullOptional
with,isPresent() == false
dan non-null,Optional
membungkus nilai aktual.@NotNull Optional
.Optional
sama sekali, maka nyatakan 1 (null
Opsional) biasanya menunjukkan kesalahan pemrograman, jadi Anda mungkin juga tidak menanganinya (biarkan sajaNullPointerException
)The posting terbaik yang pernah kulihat pada topik ditulis oleh Daniel Olszewski :
sumber
null
atauOptional
.Hampir tidak ada alasan bagus untuk tidak menggunakan
Optional
parameter. Argumen melawan ini bergantung pada argumen dari otoritas (lihat Brian Goetz - argumennya adalah kita tidak dapat menegakkan opsional bukan nol) atau bahwaOptional
argumen 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
Optional
parameter. Salah satu cara terbaik untuk menggunakan ini adalah memiliki beberapa parameter opsional dan menggunakanliftM2
menggunakan 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.
sumber
@Nonnull
dan@Nullable
dari javax.annotation saja? Saya menggunakannya secara luas di perpustakaan yang saya kembangkan, dan dukungan yang diberikan oleh IDE (IntelliJ) sangat bagus.@NonNull
benar-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.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 memintaOptional
argumen:Optional
Optional
jika nilai yang diberikan kosongAnda pikirOptional
sangat mengagumkan sehingga siapa pun yang menggunakan API Anda harus diminta untuk mempelajarinya ;-)sumber
Pola dengan
Optional
adalah untuk seseorang agar tidak kembalinull
. Masih sangat mungkinnull
untuk menggunakan metode.Meskipun ini belum benar-benar resmi, Anda dapat menggunakan anotasi gaya JSR-308 untuk menunjukkan apakah Anda menerima
null
nilai 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.sumber
Optional
juga tidak memperbaiki masalah, maka saran saya untuk anotasi.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.
sumber
Optional
tidak ada gunanya sama sekali?Lihat JavaDoc di JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html , sebuah catatan API ditambahkan:
sumber
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.
sumber
Alasan lain untuk berhati-hati ketika memberikan
Optional
parameter sebagai adalah bahwa suatu metode harus melakukan satu hal ... Jika Anda lulus suatuOptional
param, Anda dapat melakukan lebih dari satu hal, mungkin sama dengan melewatkan param boolean.sumber
if(param.isPresent())
ini bukan pendekatan terbaik untuk menggunakan Opsional, sebagai gantinya Anda dapat menggunakan:param.forEach(() -> {...})
Menerima Opsional sebagai parameter menyebabkan pembungkus yang tidak perlu pada tingkat pemanggil.
Misalnya dalam hal:
Misalkan Anda memiliki dua string bukan-nol (mis. Dikembalikan dari beberapa metode lain):
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 :
ref:
ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749
sumber
Saya pikir itu karena Anda biasanya menulis fungsi Anda untuk memanipulasi data, dan kemudian mengangkatnya untuk
Optional
menggunakanmap
dan fungsi yang serupa. Ini menambahkanOptional
perilaku default untuk itu. Tentu saja, mungkin ada kasus, ketika perlu untuk menulis fungsi bantu Anda sendiri yang berfungsiOptional
.sumber
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.
sumber
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.
sumber
Satu lagi pendekatan, yang bisa Anda lakukan adalah
Setelah Anda membangun suatu fungsi (pemasok dalam kasus ini), Anda akan dapat meneruskan ini sebagai variabel lain dan akan dapat memanggilnya menggunakan
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.
sumber
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:
sumber
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.
sumber
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.
sumber
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, sepertiOptional.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:
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:
lebih bersih dari ini:
sumber