2009-04-07 24 views
5

Tôi muốn tạo một thường trình thực hiện một số thao tác ghi nhật ký, thực hiện một số hành động khác và sau đó ném ngoại lệ. Tôi muốn thói quen này được gọi từ nhiều địa điểm khác nhau. Tuy nhiên, việc tạo ra các ngoại lệ trong thói quen này có nghĩa là chúng sẽ có thói quen này trong dấu vết ngăn xếp của chúng. Tôi thay vì ngăn xếp theo dõi không báo cáo thói quen tiện ích này. Có cách nào để làm điều này mà không tạo ra Ngoại lệ trong người gọi và chuyển nó đến thói quen tiện ích?Làm cách nào để ném ngoại lệ từ phạm vi của người gọi?

public static void die(String message) throws MyException { 
    log(message); 
    ... 
    throw new MyException(); 
} 

Đối với lập trình viên là Perl/Java song ngữ: làm cách nào để cá chép trong Java?

+0

Thành ngữ có vẻ lạ từ Javaland –

+0

Bạn đang sử dụng stacktrace cho bất kỳ điều gì ngoài gỡ lỗi? Tôi không thể hiểu tại sao điều này lại quan trọng. –

+0

đây là một ý tưởng tồi – ykaganovich

Trả lời

10

Bạn có thể đặt ngăn xếp dấu vết của bất kỳ ngoại lệ bạn muốn ném:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 

public class CarpTest { 
    public static void main(String[] args) { 
     new CarpTest().run(); 
    } 

    public void run() { 
     methodThatCarps(); 
    } 

    private void methodThatCarps() { 
     carp("Message"); 
    } 

    private void carp(String message) { 
     RuntimeException e = new RuntimeException(message); 
     e.fillInStackTrace(); 
     List<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace())); 
     stack.remove(0); 
     e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()])); 
     throw e; 
    } 
} 

này sẽ in stacktrace sau khi chạy:

Exception in thread "main" java.lang.RuntimeException: Message 
    at CarpTest.methodThatCarps(CarpTest.java:18) 
    at CarpTest.run(CarpTest.java:14) 
    at CarpTest.main(CarpTest.java:10) 

Lưu ý rằng khi bạn muốn phương pháp "cá chép "không xuất hiện trong stacktrace. Tuy nhiên các thao tác của stacktraces shoud chỉ được thực hiện với greates chăm sóc.

+0

Đó là nó; cảm ơn bạn! Tôi nghĩ rằng tôi cũng có thể kết hợp điều đó với cách tiếp cận của phân lớp Ngoại lệ và ghi đè fillInStackTrace() và đặt mã để loại bỏ StackTraceElement đầu tiên trong đó. – skiphoppy

2

Không có cách nào để xóa hàm ném khỏi ngăn xếp ngăn xếp. Toàn bộ mục đích của dấu vết ngăn xếp là ghi nhật ký đường dẫn ngoại lệ để cho phép một hàm không tham gia sẽ đánh bại mục đích.

Cách duy nhất bạn có thể thay đổi điều này là nếu bạn trả lại ngoại lệ thay vì ném nó. Nhưng điều đó buộc bạn phải phụ thuộc vào người gọi để biết để ném ngoại lệ.

throw die("someReason).fillInStackTrace(); 

chức năng Modified

public static Exception die(String message) { 
    log(message); 
    ... 
    return new MyException(); 
} 

EDIT

gia tăng các fillInStackTrace() gọi để đảm bảo ngăn xếp được thiết lập lại đến mức ném.

http://java.sun.com/j2se/1.3/docs/api/java/lang/Throwable.html#Throwable()

+0

Tôi nghĩ rằng theo dõi ngăn xếp cho thấy nơi ngoại lệ được tạo ra, không phải nơi nó đã được ném từ, vì vậy tôi không nghĩ rằng thậm chí trả lại nó sẽ thực hiện điều đó. Tôi có thể sai. Sẽ kiểm tra.:) – skiphoppy

+0

@skiphoppy, tôi khá chắc chắn nó là từ điểm ném. Nếu không, JVM sẽ báo cáo các dấu vết ngăn xếp sai trong trường hợp ngoại lệ được truyền xung quanh một chút. – JaredPar

+0

Throwable() gọi fillInStackTrace() - nó được thực hiện tại thời điểm tạo –

0

Không thể làm ... Tôi cố gắng làm một cái gì đó như thế này một khi trở lại (Tôi đã cố gắng để nắm bắt stack trace để đăng nhập phương pháp gọi trước AOP tồn tại).

Dấu vết ngăn xếp được điền khi ngoại lệ được tạo và được thực hiện nguyên bản. Đối với những điều tôi đã làm việc trên, tôi đã kết thúc đọc theo dõi ngăn xếp và nhìn vào yếu tố thứ hai, nhưng điều đó sẽ không giúp bạn ở đây ...

0

Bạn có thể xem xét phương pháp của bạn nhận được một Logger như một tham số để phương pháp. Điều này sẽ cho phép bạn kiểm soát đầu ra ghi nhật ký dựa trên lớp gọi.

Tôi khuyên bạn không muốn ngoại lệ của mình loại trừ phần này của dấu vết ngăn xếp. Khi bạn rời đi và một số người mới được duy trì mã của bạn, họ sẽ không đánh giá cao việc xử lý lỗi không chuẩn này.

0

Bạn có ném dấu vết ngăn xếp chỉ để có thể phân tích nó không? Trong trường hợp đó, bạn có thể gọi phương thức getStackTrace() trên Ngoại lệ trả về một StackTraceElement []. Ở đó bạn có thể lọc các phần tử bạn không muốn (phương thức "chết").

1

Mmm .. bạn có thể phân lớp ngoại lệ và ghi đè tất cả các phương thức trong đó và bao gồm ngoại lệ ban đầu. Bên trong, tạo ra một dấu vết ngăn xếp mới bằng cách sử dụng phương thức getStackTrace() từ ngoại lệ được bao bọc. Tôi đã không nhìn vào nguồn gốc của ngoại lệ, nhưng bạn có thể thậm chí không phải ghi đè lên nhiều phương pháp đó.

4

Nếu bạn muốn sử dụng một ngoại lệ để kiểm soát dòng chảy và những gì xảy ra sau đó, một lời khuyên tốt nó để ghi đè lên) phương pháp fillInStackTrace (:

public Throwable fillInStackTrace() { 
    return this; 
} 

Kết quả là bạn sẽ có một ngoại lệ mà không có sự stacktrace và với một giảm chi phí (điền vào theo dõi ngăn xếp mất thời gian).

1

Có thể bạn nên xem xét tiếp cận vấn đề theo một hướng khác. Thay vì sửa đổi dấu vết ngăn xếp, tại sao không chỉ có phương pháp tạo ngoại lệ của bạn (die trong ví dụ của bạn) trả lại ngoại lệ thay vì ném nó? Sau đó, cuộc gọi của bạn là throw die();.

Ví dụ:

// revised die() method: 
public static MyException die(String message){ 
    log(message); 
    //... 
    return new MyException(); 
} 


// calling code: 
throw die("a-whoopsie daisy!"); 

Bây giờ, cấp, throw die() có vẻ một chút un-thẩm mỹ, vì vậy bạn có thể đổi tên die() để newException() hoặc một cái gì đó. Nhưng yêu cầu rằng phương thức xử lý ngoại lệ không hiển thị trong ngăn xếp ngăn xếp được đáp ứng - die() (hoặc newException()) trả về trước khi ngoại lệ được ném và do đó không phải là một phần của ngăn xếp được truy tìm.

Chỉnh sửa: Tệ của tôi. Tôi đã dành rất nhiều thời gian làm việc với C# mà tôi quên rằng trong dấu vết ngăn xếp ngoại lệ Java được tạo ra tại instantiation, nơi trong C# /. NET ngoại lệ ngăn xếp dấu vết được tạo ra tại thời gian ném.

Vì vậy, mẹo này sẽ hoạt động trong C#, chứ không phải trong Java.

+0

Tôi không nghĩ rằng điều này sẽ làm việc. Stacktrace được điền khi ngoại lệ được khởi tạo, không phải cái mà nó được ném ra. –

+0

Vâng, thật tuyệt khi biết rằng nó sẽ hoạt động trong C#. Tôi có thể cần một ngày nào đó. :) Tôi đã bình chọn cho bạn trở lại 0 từ -1. :) – skiphoppy

+0

gọi fillInStackTrace trước khi ném – ordnungswidrig

1

Dựa trên những gì ordnungswidrig nói về cách đặt dấu vết ngăn xếp và những gì không xác định (google) đã nói về trọng lượng fillInStackTrace(), tôi đã tạo ra một CarpException thực hiện chính xác những gì tôi muốn. Lưu ý rằng tôi đã tìm thấy tôi đã phải loại bỏ bốn khung dấu vết ngăn xếp thay vì chỉ một, vì tôi đã chọn lên khung từ cả Throwable và Exception.

public class CarpException extends Exception { 
    @Override 
    public Throwable fillInStackTrace() { 
    super.fillInStackTrace(); 
    StackTraceElement[] origStackTrace = getStackTrace(); 
    StackTraceElement[] newStackTrace = new StackTraceElement[origStackTrace.length - 4]; 
    System.arraycopy(origStackTrace, 4, newStackTrace, 0, origStackTrace.length - 4); 
    setStackTrace(newStackTrace); 
    return this; 
    } 
} 
Các vấn đề liên quan