UtilException
คลาสตัวช่วยนี้ให้คุณใช้ข้อยกเว้นที่ตรวจสอบในสตรีม Java เช่นนี้:
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
หมายเหตุClass::forName
พ่นClassNotFoundException
ซึ่งจะตรวจสอบ สตรีมเองก็ส่งClassNotFoundException
ข้อยกเว้นบางข้อยกเว้นที่ไม่ได้ตรวจสอบ
public final class UtilException {
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
void run() throws E;
}
/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
return t -> {
try { consumer.accept(t); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try { biConsumer.accept(t, u); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
return t -> {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
return () -> {
try { return function.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
{
try { t.run(); }
catch (Exception exception) { throwAsUnchecked(exception); }
}
/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
{
try { return supplier.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
ตัวอย่างอื่น ๆ อีกมากมายเกี่ยวกับวิธีใช้งาน (หลังจากการนำเข้าแบบคงที่UtilException
):
@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(System.out::println));
}
@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
List<Class> classes1
= Stream.of("Object", "Integer", "String")
.map(rethrowFunction(className -> Class.forName("java.lang." + className)))
.collect(Collectors.toList());
List<Class> classes2
= Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
}
@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
Collector.of(
rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
}
@Test
public void test_uncheck_exception_thrown_by_method() {
Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));
Class clazz2 = uncheck(Class::forName, "java.lang.String");
}
@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
Class clazz3 = uncheck(Class::forName, "INVALID");
}
แต่อย่าใช้ก่อนที่จะเข้าใจถึงข้อดีข้อเสียและข้อ จำกัด ต่อไปนี้ :
•หากรหัสการโทรคือการจัดการข้อยกเว้นที่ตรวจสอบคุณจะต้องเพิ่มลงในส่วนการโยนของวิธีการที่มีกระแส คอมไพเลอร์จะไม่บังคับให้คุณเพิ่มอีกต่อไปดังนั้นจึงง่ายต่อการลืม
•หากรหัสโทรศัพท์จัดการกับข้อยกเว้นที่เลือกไว้คอมไพเลอร์จะเตือนคุณให้เพิ่มส่วนคำสั่ง throws ลงในการประกาศเมธอดที่มีสตรีม (ถ้าคุณไม่ทำมันจะบอกว่า: ข้อยกเว้นจะไม่ถูกโยนลงในเนื้อความของคำสั่ง try ที่สอดคล้องกัน )
•ไม่ว่าในกรณีใดคุณจะไม่สามารถล้อมรอบสตรีมเพื่อตรวจจับข้อยกเว้นที่ตรวจสอบภายในวิธีที่มีสตรีม (หากคุณลองคอมไพเลอร์จะพูดว่า: ข้อยกเว้นจะไม่ถูกโยนลงในเนื้อความของคำสั่ง try ที่เกี่ยวข้อง)
•หากคุณกำลังเรียกใช้วิธีการที่ไม่สามารถทิ้งข้อยกเว้นที่ประกาศได้อย่างแท้จริงคุณไม่ควรรวมประโยคการส่ง ตัวอย่างเช่น: String ใหม่ (byteArr, "UTF-8") พ่น UnsupportedEncodingException แต่ UTF-8 รับประกันโดย Java spec จะมีอยู่เสมอ ที่นี่ประกาศพ่นเป็นสิ่งที่น่ารำคาญและวิธีการแก้ปัญหาใด ๆ ที่จะเงียบมันด้วยแผ่นสำเร็จรูปน้อยที่สุดยินดีต้อนรับ
•หากคุณเกลียดการตรวจสอบข้อยกเว้นและรู้สึกว่าไม่ควรเพิ่มในภาษาจาวาเพื่อเริ่มต้น (ผู้คนจำนวนมากคิดว่าวิธีนี้และฉันไม่ใช่หนึ่งในนั้น) จากนั้นอย่าเพิ่มข้อยกเว้นที่ตรวจสอบลงใน พ่นประโยคของวิธีการที่มีกระแส ข้อยกเว้นที่ถูกเลือกจะทำตัวเหมือนข้อยกเว้นที่ไม่ได้ตรวจสอบ
•หากคุณใช้งานอินเตอร์เฟสที่เข้มงวดซึ่งคุณไม่มีตัวเลือกสำหรับการเพิ่มการประกาศการโยน แต่การโยนข้อยกเว้นมีความเหมาะสมอย่างสมบูรณ์แล้วให้ห่อข้อยกเว้นเพื่อให้ได้รับสิทธิพิเศษในการขว้างมัน ซึ่งไม่สนับสนุนข้อมูลเกี่ยวกับสิ่งที่ผิดพลาดจริง ตัวอย่างที่ดีคือ Runnable.run () ซึ่งไม่มีข้อยกเว้นที่ตรวจสอบ ในกรณีนี้คุณอาจตัดสินใจที่จะไม่เพิ่มข้อยกเว้นที่ตรวจสอบไปยังส่วนการส่งข้อความของวิธีการที่มีกระแสข้อมูล
•ในกรณีใด ๆ หากคุณตัดสินใจที่จะไม่เพิ่ม (หรือลืมที่จะเพิ่ม) ข้อยกเว้นที่ตรวจสอบกับการส่งคำสั่งย่อยของวิธีการที่มีกระแสข้อมูลให้ตระหนักถึง 2 ผลของการโยนข้อยกเว้นตรวจสอบเหล่านี้:
1) การเรียกรหัสจะไม่สามารถจับมันด้วยชื่อ (ถ้าคุณลองคอมไพเลอร์จะพูดว่า: ข้อยกเว้นไม่เคยถูกโยนลงในเนื้อความของคำสั่ง try ที่เกี่ยวข้อง) มันจะทำให้เกิดฟองและอาจถูกจับได้ในวงหลักของโปรแกรมโดย "catch Exception" หรือ "catch Throwable" ซึ่งอาจเป็นสิ่งที่คุณต้องการ
2) มันละเมิดหลักการของความประหลาดใจน้อยที่สุด: มันจะไม่เพียงพอที่จะจับ RuntimeException เพื่อให้สามารถรับประกันว่าจะได้รับข้อยกเว้นที่เป็นไปได้ทั้งหมด ด้วยเหตุผลนี้ฉันเชื่อว่าสิ่งนี้ไม่ควรทำในรหัสเฟรมเวิร์ก แต่เฉพาะในรหัสธุรกิจที่คุณควบคุมได้อย่างสมบูรณ์
โดยสรุป: ฉันเชื่อว่าข้อ จำกัด ที่นี่ไม่ร้ายแรงและUtilException
อาจใช้ชั้นเรียนโดยไม่ต้องกลัว อย่างไรก็ตามมันก็ขึ้นอยู่กับคุณ!