Java 如何从调用者&x27;什么范围?

Java 如何从调用者&x27;什么范围?,java,exception,stack-trace,Java,Exception,Stack Trace,我想创建一个例程,它执行一些日志记录,执行一些其他操作,然后抛出一个异常。我想从许多不同的地方调用这个例程。但是,在此例程中创建异常意味着它们将在堆栈跟踪中包含此例程。我宁愿堆栈跟踪不报告此实用程序例程。有没有一种方法可以做到这一点,而不用在调用者中创建异常并将其传递给实用程序例程 public static void die(String message) throws MyException { log(message); ... throw new MyException();

我想创建一个例程,它执行一些日志记录,执行一些其他操作,然后抛出一个异常。我想从许多不同的地方调用这个例程。但是,在此例程中创建异常意味着它们将在堆栈跟踪中包含此例程。我宁愿堆栈跟踪不报告此实用程序例程。有没有一种方法可以做到这一点,而不用在调用者中创建异常并将其传递给实用程序例程

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

对于使用Perl/Java双语的程序员:如何在Java中使用carp?

无法从堆栈跟踪中删除抛出函数。堆栈跟踪的全部目的是记录异常路径,因此允许函数选择退出将无法实现此目的

唯一可以更改的方法是返回异常而不是抛出异常。但这迫使您依赖调用方知道如何抛出异常

throw die("someReason).fillInStackTrace();
修正函数

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

添加了fillInStackTrace()调用,以确保堆栈重置到抛出点


没有什么可以做的。。。不久前我尝试过这样做(在AOP存在之前,我试图捕获堆栈跟踪以记录方法调用)


当创建异常时,将填充堆栈跟踪,这是本机完成的。对于我正在做的事情,我最终读取了堆栈跟踪并查看第二个元素,但这对您没有帮助。

您可以考虑让方法接收一个记录器作为该方法的参数。这将允许您根据调用类控制日志输出


我建议不要让您的异常排除堆栈跟踪的这一部分。当你离开并且有新的人来维护你的代码时,他们不会喜欢这种非标准的错误处理。

你抛出堆栈跟踪只是为了能够分析它吗?在这种情况下,可以对返回StackTraceElement[]的异常调用getStackTrace()方法。在那里,您可以过滤不需要的元素(例如“die”方法)。

Mmm。。您可以将exception子类化,覆盖其中的所有方法,并包装原始异常。在内部,使用getStackTrace()方法从包装的异常生成新的堆栈跟踪。我还没有研究异常的来源,但您可能甚至不必重写那么多方法。

如果您想使用异常来控制流以及随后发生的事情,建议您重写fillInStackTrace()方法:


因此,在没有stacktrace的情况下会出现异常,并且开销会减少(填充堆栈跟踪需要时间)

您可以设置要引发的任何异常的堆栈跟踪:

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;
    }
}

请注意,正如您所希望的那样,“carp”方法不会出现在stacktrace中。然而,堆栈跟踪的操作只能用GRIATE CARCH来处理。

也许你应该考虑从不同的方向来解决这个问题。与其修改堆栈跟踪,为什么不让异常生成器方法(

die
)返回异常而不是抛出异常呢?然后您的调用是
throw die()

例如:

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


// calling code:
throw die("a-whoopsie daisy!");
当然,
throw die()
可能看起来有点不美观,所以您可以将
die()
重命名为
newException()
或其他名称。但是异常处理方法不显示在堆栈跟踪中的要求得到满足--
die()
(或
newException()
)在抛出异常之前返回,因此不是要跟踪的堆栈的一部分

编辑:我的坏消息。我花了太多时间使用C#,以至于我忘记了Java中的异常堆栈跟踪是在实例化时生成的,而C#/.NET中的异常堆栈跟踪是在抛出时生成的


因此,这个技巧在C#中有效,但在Java中无效

根据Ordnugswidrig关于设置堆栈跟踪的说法,以及unknown(google)关于覆盖fillInStackTrace()的说法,我创建了一个CarpException,它完全符合我的要求。注意,我发现我必须去掉四个堆栈跟踪帧,而不是一个,因为我同时从Throwable和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;
  }
}

我认为堆栈跟踪显示异常是在哪里创建的,而不是从哪里抛出的,所以我认为即使返回它也不能实现这一点。我可能错了。将检查。:)@斯基菲比,我很确定这是从掷球的角度看的。否则,JVM会在异常稍微传递的情况下报告错误的堆栈跟踪。Throwable()调用fillInStackTrace()--这是在创建时完成的time@Scott哇,没错(在CLR上正好相反)。我将更新我的示例这个习惯用法在JavaLand中看起来很奇怪你是否使用stacktrace进行调试以外的任何操作?我真的不明白这有什么关系。@ykaganovich,你做过吗?它一直都是用Perl完成的,而且是有原因的。通常,当人们谈论一种语言所缺乏的功能时,会有很多人认为你不应该这样做,而他们自己从来没有这样做过我做过什么?你有一个记录器吗?你有错误处理程序吗?对我有没有弄乱过堆栈微量元素?是的,但不是要从printStackTrace中删除某些内容。我是否曾经“宁愿堆栈跟踪不报告此实用程序例程”?不,因为我认为这是个坏主意。我认为这行不通。stacktrace是在实例化异常时填充的,而不是在抛出异常时填充的。总有一天我会需要的。:)我投票支持你从-1上升到0在抛出之前调用fillInStackTrace,仅此而已;非常感谢。我想我还可以将其与子类化Exception和重写fillInStackTrace()的方法结合起来,并将代码放入以删除第一个StackTraceEle
// revised die() method:
public static MyException die(String message){
  log(message);
  //...
  return new MyException();
}


// calling code:
throw die("a-whoopsie daisy!");
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;
  }
}