2009-06-27 32 views
8

Có cách nào để chú thích một phương thức để tất cả ngoại lệ được ném được chuyển đổi sang ngoại lệ thời gian chạy tự động không?Bọc ngoại lệ theo ngoại lệ thời gian chạy với chú thích

@MagicAnnotation 
// no throws clause! 
void foo() 
{ 
    throw new Exception("bar")' 
} 
+1

IOW một cách để tắt kiểm tra trình biên dịch trên kiểm tra ngoại lệ. –

+0

Có - Tôi nghĩ rằng tôi đã thấy điều này ở đâu đó, ngay cả trong codebase của chúng tôi. – ripper234

Trả lời

1

Không có cách nào để làm điều đó, ít nhất là cho bây giờ tôi sử dụng workaround như thế này (giản thể):

@SuppressWarnings({"rawtypes", "unchecked"}) 
public class Unchecked { 
    public static interface UncheckedDefinitions{ 
     InputStream openStream(); 
     String readLine(); 
      ... 
    } 

    private static Class proxyClass = Proxy.getProxyClass(Unchecked.class.getClassLoader(), UncheckedDefinitions.class); 

    public static UncheckedDefinitions unchecked(final Object target){ 
     try{ 
      return (UncheckedDefinitions) proxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler(){ 
       @Override 
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
        if (target instanceof Class){ 
         return MethodUtils.invokeExactStaticMethod((Class) target, method.getName(), args); 
        } 

        return MethodUtils.invokeExactMethod(target, method.getName(), args); 
       } 
      }); 
     } 
     catch(Exception e){ 
      throw new RuntimeException(e); 
     } 
    } 
} 

Và việc sử dụng trông giống như:

import static ....Unchecked.*; 

... 

Writer w = ...; 
unchecked(w).write(str, off, len); 

Bí quyết là giao diện được " không bao giờ kết thúc "và mọi lúc tôi cần một phương thức không được kiểm tra ở đâu đó, tôi sẽ bọc đối tượng đó vào trong kiểm tra và để cho IDE tạo ra chữ ký phương thức trong giao diện.

thực hiện là sau đó generic (phản xạ và "chậm" nhưng thường đủ nhanh)

Có một số mã sau xử lý và bytecode-thợ dệt nhưng điều này là không thể (thậm chí không aop hoặc JVM ngôn ngữ dựa khác) cho dự án hiện tại của tôi, vì vậy đây là "phát minh".

2

Bạn có thể làm điều này với AspectJ. Bạn khai báo một điểm tham gia (trong trường hợp này yêu cầu phương thức foo) và 'làm mềm' ngoại lệ.

Sửa Để xây dựng một chút về vấn đề này:

Giả sử bạn có các lớp sau Bar:

public class Bar { 

    public void foo() throws Exception { 
    } 
} 

... và bạn có một bài kiểm tra như thế này:

import junit.framework.TestCase; 

public class BarTest extends TestCase { 

    public void testTestFoo() { 
     new Bar().foo(); 
    } 
} 

Sau đó, rõ ràng là thử nghiệm sẽ không biên dịch. Nó sẽ cho một lỗi:

Unhandled exception type Exception BarTest.java(line 6) 

Bây giờ để khắc phục điều này với AspectJ, bạn viết một khía cạnh rất đơn giản:

public aspect SoftenExceptionsInTestCode { 

    pointcut inTestCode() : execution(void *Test.test*()); 

    declare soft : Exception : inTestCode(); 
} 

Khía cạnh cơ bản nói rằng bất kỳ mã từ bên trong một thử nghiệm (ví dụ: một phương pháp bắt đầu bằng "test" trong một lớp kết thúc bằng "Test" và trả về "void") mà ném một ngoại lệ phải được trình biên dịch AspectJ chấp nhận. Nếu một ngoại lệ xảy ra, nó sẽ được gói và ném như là một RuntimeException bởi trình biên dịch AspectJ. Thật vậy, nếu bạn chạy thử nghiệm này như là một phần của dự án AspectJ từ bên trong Eclipse (với cài đặt AJDT) thì thử nghiệm sẽ thành công, trong khi không có khía cạnh nào thì nó sẽ không biên dịch được.

+0

Tôi nghĩ đây là một câu trả lời công bằng (mặc dù tôi không biết gì về AOP ngoài các khái niệm). Tự hỏi tại sao nó đã được downvoted? – akarnokd

+0

Mã mẫu sẽ rất hay - có nhiều khái niệm mới khi nhìn vào AOP khó có thể đạt được. –

1

Tôi nghĩ rằng có thể với kỹ thuật tái tạo bytecode, trình biên dịch tùy chỉnh hoặc có lẽ lập trình theo hướng khía cạnh . Ngược lại với Java, C# chỉ có các ngoại lệ không được kiểm tra .

Tôi có thể hỏi tại sao bạn muốn chặn ngoại lệ đã kiểm tra không?

theo Maarten Winkels điều này là có thể.
và họ đang suy nghĩ về việc giới thiệu những người đã kiểm tra, theo một số kênh 9 video.

Chỉnh sửa: Đối với câu hỏi: Có thể theo nghĩa bạn có thể chú thích các phương pháp của bạn để gắn cờ chúng là ứng cử viên cho việc loại trừ ngoại lệ đã chọn. Sau đó, bạn sử dụng một số thời gian biên dịch hoặc thời gian chạy lừa để áp dụng thực tế đàn áp/gói. Tuy nhiên, vì tôi không thấy môi trường xung quanh trường hợp của bạn, việc bao gồm một ngoại lệ theo những cách này có thể gây nhầm lẫn cho khách hàng của phương thức đó - chúng có thể không được chuẩn bị để đối phó với RuntimeException. Ví dụ: phương thức ném một IOException và các máy khách của bạn bắt nó như là FileNotFoundException để hiển thị một hộp thoại báo lỗi. Tuy nhiên nếu bạn bọc ngoại lệ của bạn vào một RuntimeException, hộp thoại lỗi sẽ không bao giờ được hiển thị và có thể nó cũng giết chết chuỗi người gọi. (IMHO).

+0

Mã thử nghiệm, tôi không thực sự quan tâm đến những ngoại lệ nào tại thời điểm đó. Ngoài ra, việc tôi nhận trong trường hợp ngoại lệ đã kiểm tra-có-hoặc-không là một số khá vững chắc (nhưng sẽ phù hợp với tiêu chuẩn và không có tất cả ngoại lệ của tôi mở rộng RuntimeException cho mã sản xuất). – ripper234

+0

Cảm ơn bạn. Tôi nghĩ rằng việc có tùy chọn sử dụng ngoại lệ đã kiểm tra là tốt - nó cho phép bạn 'hướng dẫn' khách hàng của bạn.Tuy nhiên, đôi khi tôi cảm thấy nó, trong một số trường hợp cụ thể, rằng một ngoại lệ nên có được loại khác. Tuy nhiên, về mức độ thụ thai, tôi nghĩ câu trả lời của tôi vẫn đứng vững. – akarnokd

0

Bạn có thể làm điều này trong mọi trường hợp thông qua việc sử dụng thực tế là Class.newInstancekhông quấn một Exception ném bởi các nhà xây dựng không-arg trong một InvocationTargetException; chứ không phải nó ném nó âm thầm:

class ExUtil { 
    public static void throwSilent(Exception e) { //NOTICE NO THROWS CLAUSE 
     tl.set(e); 
     SilentThrower.class.newInstance(); //throws silently 
    } 

    private static ThreadLocal<Exception> tl = new ThreadLocal<Exception>(); 
    private static class SilentThrower { 
     SilentThrower() throws Exception { 
      Exception e = tl.get(); 
      tl.remove(); 
      throw e; 
     } 
    } 
} 

Sau đó, bạn có thể sử dụng tiện ích này ở bất cứ đâu:

ExUtil.throwSilent(new Exception()); 
//or 
try { 
    ioMethod(); 
} catch (IOException e) { ExUtil.throwSilent(e); } 

Bằng cách này, đây là một ý tưởng thực sự xấu :-)

0

tôi sử dụng hệ thống hoàn chỉnh/mẫu của Eclipse để bọc bất kỳ khối mã nào một cách dễ dàng.

Đây là mẫu của tôi:

try { // Wrapp exceptions 

${line_selection}${cursor} 

} catch (RuntimeException e) { // Forward runtime exception 
throw e; 
} catch (Exception e) { // Wrap into runtime exception 
throw new RuntimeException(
    "Exception wrapped in #${enclosing_method}", 
    e); 
} 
1

Các trường hợp ngoại lệ Checked là Trách nhiệm của việc thực hiện phương pháp. Thực hiện rất cẩn thận sự kiện này. nếu bạn không thể sử dụng hiện vật workaround như thế.

6

Dự án của Lombok @SneakyThrows có lẽ là những gì bạn đang tìm kiếm. Không thực sự gói ngoại lệ của bạn (bởi vì nó có thể là một vấn đề trong rất nhiều trường hợp), nó chỉ không ném một lỗi trong quá trình biên dịch.

@SneakyThrows 
void foo() { 
    throw new Exception("bar")' 
} 
Các vấn đề liên quan