Saya tahu cara membuat referensi ke metode yang memiliki String
parameter dan mengembalikan int
, itu:
Function<String, Integer>
Namun, ini tidak berfungsi jika fungsi melempar pengecualian, katakan itu didefinisikan sebagai:
Integer myMethod(String s) throws IOException
Bagaimana saya mendefinisikan referensi ini?
Jawaban:
Anda harus melakukan salah satu dari yang berikut ini.
Jika itu kode Anda, maka tentukan antarmuka fungsional Anda sendiri yang menyatakan pengecualian yang diperiksa:
dan gunakan:
Jika tidak, bungkus
Integer myMethod(String s)
dengan metode yang tidak menyatakan pengecualian yang diperiksa:lalu:
atau:
sumber
Consumer
atauFunction
jika Anda menggunakan metode default - lihat jawaban saya di bawah ini.(String t) -> myWrappedMethod(t)
, referensi metodethis::myWrappedMethod
juga dapat digunakan.Anda sebenarnya dapat memperluas
Consumer
(danFunction
lain - lain) dengan antarmuka baru yang menangani pengecualian - menggunakan metode default Java 8 !Pertimbangkan antarmuka ini (meluas
Consumer
):Kemudian, misalnya, jika Anda memiliki daftar:
Jika Anda ingin mengkonsumsinya (mis. Dengan
forEach
) dengan beberapa kode yang melempar pengecualian, Anda biasanya telah menyiapkan blok coba / tangkap:Tetapi dengan antarmuka baru ini, Anda bisa instantiate dengan ekspresi lambda dan kompiler tidak akan mengeluh:
Atau bahkan hanya melemparkannya agar lebih ringkas !:
Pembaruan : Sepertinya ada bagian perpustakaan utilitas yang sangat bagus dari Durian yang disebut Kesalahan yang dapat digunakan untuk menyelesaikan masalah ini dengan lebih banyak fleksibilitas. Sebagai contoh, dalam implementasi saya di atas saya telah secara eksplisit mendefinisikan kebijakan penanganan kesalahan (
System.out...
atauthrow RuntimeException
), sedangkan Kesalahan Durian memungkinkan Anda untuk menerapkan kebijakan dengan cepat melalui serangkaian metode utilitas yang besar. Terima kasih telah berbagi , @NedTwigg !.Penggunaan sampel:
sumber
Saya pikir kelas Durian
Errors
menggabungkan banyak pro dari berbagai saran di atas.Untuk memasukkan Durian dalam proyek Anda, Anda dapat:
com.diffplug.durian:durian:3.3.0
Throwing.java
danErrors.java
sumber
Ini tidak khusus untuk Java 8. Anda mencoba mengkompilasi sesuatu yang setara dengan:
sumber
Penafian: Saya belum menggunakan Java 8, hanya membaca tentang itu.
Function<String, Integer>
tidak membuangIOException
, jadi Anda tidak bisa memasukkan kode apa pun di dalamnya ituthrows IOException
. Jika Anda memanggil metode yang mengharapkanFunction<String, Integer>
, maka lambda yang Anda berikan ke metode itu tidak dapat dilemparIOException
, titik. Anda dapat menulis lambda seperti ini (saya pikir ini adalah sintaks lambda, tidak yakin):Atau, jika metode yang Anda berikan lambda adalah metode yang Anda tulis sendiri, Anda bisa mendefinisikan antarmuka fungsional baru dan menggunakannya sebagai tipe parameter alih-alih
Function<String, Integer>
:sumber
@FunctionalInterface
anotasi tidak diperlukan untuk dapat digunakan untuk lambdas. Disarankan untuk memeriksa kewarasan.Jika Anda tidak keberatan menggunakan lib pihak ke-3 ( VAVR ) Anda bisa menulis
Ini juga memiliki yang disebut Try monad yang menangani kesalahan:
Silakan baca lebih lanjut di sini .
Penafian: Saya pencipta Vavr.
sumber
Anda dapat menggunakan pembungkus unthrow
atau
sumber
Namun Anda bisa membuat FungsionalInterface Anda sendiri yang melempar seperti di bawah ini ..
kemudian implementasikan menggunakan Lambdas atau referensi seperti yang ditunjukkan di bawah ini.
sumber
Kamu bisa.
Memperluas @marcg
UtilException
dan menambahkan generik<E extends Exception>
jika diperlukan: dengan cara ini, kompiler akan memaksa Anda lagi untuk menambahkan klausa melempar dan semuanya seolah-olah Anda bisa melempar pengecualian yang diperiksa secara native pada stream java 8.sumber
Saya punya masalah dengan Class.forName dan Class.newInstance di dalam lambda, jadi saya baru saja melakukannya:
Di dalam lambda, alih-alih memanggil Class.forName ("myClass"). NewInstance () Saya hanya menelepon uncheckedNewInstanceForName ("myClass")
sumber
Solusi lain menggunakan pembungkus Fungsi akan mengembalikan salah satu instance dari pembungkus hasil Anda, katakan Sukses, jika semuanya berjalan dengan baik, salah satu contoh dari, katakanlah Kegagalan.
Beberapa kode untuk memperjelas beberapa hal:
Kasus penggunaan sederhana:
sumber
Masalah ini juga mengganggu saya; ini sebabnya saya membuat proyek ini .
Dengan itu Anda bisa melakukan:
Ada totla dari 39 interface yang didefinisikan oleh JDK yang memiliki
Throwing
padanan seperti itu ; mereka semua@FunctionalInterface
digunakan dalam stream (basisStream
tetapi jugaIntStream
,LongStream
danDoubleStream
).Dan karena masing-masing dari mereka memperpanjang rekan non-lempar, Anda dapat langsung menggunakannya dalam lambdas juga:
Perilaku default adalah bahwa ketika Anda melempar lambda melempar pengecualian yang diperiksa, a
ThrownByLambdaException
dilemparkan dengan pengecualian diperiksa sebagai penyebabnya. Karena itu Anda dapat menangkapnya dan mendapatkan penyebabnya.Fitur lain juga tersedia.
sumber
@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }
- dengan cara ini pengguna tidak perlu menangkapThrowable
, tetapi mengecek pengecualian spesifik sebagai gantinya.ThrownByLambdaException
, Anda akan memiliki pengecualian asli sebagai penyebab (atau Anda dapat menggunakanrethrow(...).as(MyRuntimeException.class)
)Throwing.runnable()
dan yang lainnya, selalu dengan kemampuan chainingAda banyak tanggapan hebat yang sudah diposting di sini. Hanya berusaha menyelesaikan masalah dengan perspektif yang berbeda. Hanya 2 sen saya, perbaiki saya jika saya salah di suatu tempat.
Melempar klausa di Fungsional Antarmuka bukanlah ide yang baik
Saya pikir ini mungkin bukan ide yang baik untuk menegakkan melempar IOException karena alasan berikut
Bagi saya ini seperti anti-pola untuk Stream / Lambda. Seluruh ide adalah bahwa penelepon akan memutuskan kode apa yang akan diberikan dan bagaimana menangani pengecualian. Dalam banyak skenario, IOException mungkin tidak berlaku untuk klien. Misalnya, jika klien mendapatkan nilai dari cache / memori alih-alih melakukan I / O yang sebenarnya.
Selain itu, pengecualian yang menangani dalam aliran menjadi sangat mengerikan. Misalnya, ini kode saya yang akan terlihat jika saya menggunakan API Anda
Jelek bukan? Selain itu, seperti yang saya sebutkan di poin pertama saya, bahwa metode doSomeOperation mungkin atau mungkin tidak melempar IOException (tergantung pada implementasi klien / pemanggil), tetapi karena klausa melempar dalam metode FungsionalInterface Anda, saya selalu harus menulis coba tangkap.
Apa yang harus saya lakukan jika saya benar-benar tahu API ini melempar IOException
Maka mungkin kita membingungkan FunctionalInterface dengan Antarmuka khas. Jika Anda tahu API ini akan melempar IOException, maka kemungkinan besar Anda juga tahu beberapa perilaku default / abstrak. Saya pikir Anda harus mendefinisikan antarmuka dan menggunakan perpustakaan Anda (dengan implementasi standar / abstrak) sebagai berikut
Namun, masalah try-catch masih ada untuk klien. Jika saya menggunakan API Anda dalam aliran, saya masih perlu menangani IOException di blok try-catch yang mengerikan.
Berikan API ramah aliran default sebagai berikut
Metode default mengambil objek konsumen sebagai argumen, yang akan bertanggung jawab untuk menangani pengecualian. Sekarang, dari sudut pandang klien, kode akan terlihat seperti ini
Bagus kan? Tentu saja, logger atau logika penanganan lainnya dapat digunakan sebagai pengganti Exception :: printStackTrace.
Anda juga dapat mengekspos metode yang mirip dengan https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.fungsi.Fungsi.Fungsi- . Berarti Anda dapat mengekspos metode lain, yang akan berisi pengecualian dari panggilan metode sebelumnya. Kerugiannya adalah Anda sekarang membuat API Anda stateful, yang berarti bahwa Anda perlu menangani keamanan utas dan yang pada akhirnya akan menjadi hit kinerja. Hanya opsi untuk dipertimbangkan.
sumber
Stream
mengangkat Exception. Jadi, saya menyukai gagasan memiliki penangan pengecualian dan memfilter hasil yang tidak valid. Perhatikan bahwa MyAmazingAPI Anda secara efektif aFunctionalInterface
(karena itu Anda dapat menambahkan anotasi @FunctionalInterface). Anda juga bisa memiliki nilai default daripada menggunakanOptional.empty()
.Idiom throw licik memungkinkan memotong
CheckedException
ekspresi Lambda. MembungkusCheckedException
aRuntimeException
tidak baik untuk penanganan kesalahan yang ketat.Ini dapat digunakan sebagai
Consumer
fungsi yang digunakan dalam koleksi Java.Berikut adalah versi sederhana dari jawaban jib .
Ini hanya membungkus lambda dalam rethrow . Itu membuat
CheckedException
rethrow semuaException
yang dilemparkan ke lambda Anda.Temukan kode lengkap dan tes unit di sini .
sumber
Anda dapat menggunakan ET untuk ini. ET adalah perpustakaan Java 8 kecil untuk konversi pengecualian / terjemahan.
Dengan ET terlihat seperti ini:
ExceptionTranslator
instance aman untuk digunakan bersama oleh banyak komponen. Anda dapat mengonfigurasi aturan konversi pengecualian yang lebih spesifik (mis.FooCheckedException -> BarRuntimeException
) Jika Anda mau. Jika tidak ada aturan lain yang tersedia, pengecualian yang dicentang secara otomatis dikonversi keRuntimeException
.(Penafian: Saya adalah penulis ET)
sumber
Yang saya lakukan adalah mengizinkan pengguna untuk memberikan nilai yang sebenarnya ia inginkan jika ada pengecualian. Jadi saya punya sesuatu yang terlihat seperti ini
Dan ini bisa disebut seperti:
sumber
Jika Anda tidak keberatan menggunakan perpustakaan pihak ketiga, dengan cyclops-react , perpustakaan yang saya berkontribusi, Anda dapat menggunakan API FluentFunctions untuk menulis
ofChecked mengambil jOOλ CheckedFunction dan mengembalikan referensi yang dilunakkan ke standar (tidak dicentang) JDK java.util.function.Function.
Atau Anda dapat tetap bekerja dengan fungsi yang diambil melalui api FluentFunctions!
Misalnya untuk mengeksekusi metode Anda, coba lagi hingga 5 kali dan mencatat status yang bisa Anda tulis
sumber
Secara default, Fungsi Java 8 tidak memungkinkan untuk membuang pengecualian dan seperti yang disarankan dalam beberapa jawaban ada banyak cara untuk mencapainya, salah satu caranya adalah:
Tentukan sebagai:
Dan tambahkan
throws
atautry/catch
pengecualian yang sama dalam metode pemanggil.sumber
Buat jenis pengembalian kustom yang akan menyebarkan pengecualian yang diperiksa. Ini adalah alternatif untuk membuat antarmuka baru yang mencerminkan antarmuka fungsional yang ada dengan sedikit modifikasi dari "throws exception" pada metode antarmuka fungsional.
Definisi
CheckedValueSupplier
Nilai Checked
Pemakaian
Apa yang sedang terjadi?
Antarmuka fungsional tunggal yang melempar pengecualian diperiksa dibuat (
CheckedValueSupplier
). Ini akan menjadi satu-satunya antarmuka fungsional yang memungkinkan pengecualian yang diperiksa. Semua antarmuka fungsional lainnya akan memanfaatkanCheckedValueSupplier
untuk membungkus kode apa pun yang melempar pengecualian yang diperiksa.The
CheckedValue
kelas akan memegang hasil mengeksekusi logika yang melempar pengecualian diperiksa. Ini mencegah penyebaran pengecualian yang dicentang hingga titik di mana kode mencoba mengakses nilai yangCheckedValue
berisi instance .Masalah dengan pendekatan ini.
CheckedValue#get()
dipanggil.Konsumen et al
Beberapa antarmuka fungsional (
Consumer
misalnya) harus ditangani dengan cara yang berbeda karena tidak memberikan nilai balik.Berfungsi sebagai pengganti Konsumen
Salah satu pendekatan adalah menggunakan fungsi alih-alih konsumen, yang berlaku saat menangani stream.
Meningkatkan
Atau, Anda selalu dapat naik ke
RuntimeException
. Ada jawaban lain yang mencakup eskalasi pengecualian yang diperiksa dari dalam aConsumer
.Jangan dikonsumsi.
Cukup hindari antarmuka fungsional secara bersamaan dan gunakan loop yang bagus.
sumber
Saya menggunakan fungsi utilitas kelebihan beban yang disebut
unchecked()
yang menangani beberapa kasus penggunaan.BEBERAPA PENGGUNAAN EAMPLE
UTILITAS PENDUKUNG
sumber
Beberapa solusi yang ditawarkan menggunakan argumen generik E untuk meneruskan jenis pengecualian yang dilemparkan.
Ambil satu langkah lebih jauh, dan alih-alih meneruskan dalam jenis pengecualian, masukkan Konsumen jenis pengecualian, seperti dalam ...
Anda dapat membuat beberapa variasi yang dapat digunakan kembali
Consumer<Exception>
yang akan mencakup kebutuhan penanganan perkecualian umum aplikasi Anda.sumber
Saya akan melakukan sesuatu yang umum:
pemakaian:
sumber
Gunakan
Jool Library
atau katakanjOOλ library
dariJOOQ
. Ini tidak hanya menyediakan pengecualian yang ditangani antarmuka tetapi juga menyediakan kelas Seq dengan metode yang berguna.Juga, ini berisi Antarmuka Fungsional dengan hingga 16 parameter. Selain itu, ia menyediakan kelas Tuple yang digunakan dalam skenario yang berbeda.
Jool Git Link
Khususnya di pencarian perpustakaan untuk
org.jooq.lambda.fi.util.function
paket. Ini berisi semua antarmuka dari Java-8 dengan diperiksa diperiksa. Lihat di bawah untuk referensi: -sumber
Saya penulis lib kecil dengan sihir generik untuk membuang Java Exception di mana saja tanpa perlu menangkapnya atau membungkusnya dengan
RuntimeException
.Pemakaian:
unchecked(() -> methodThrowingCheckedException())
sumber: https://github.com/qoomon/unchecked-exceptions-java
sumber
sumber
<code>/<code>
:)