Dynamically get the current line number

前端 未结 5 1962
一整个雨季
一整个雨季 2020-12-14 00:58

Is there a way in Java to dynamically get the current line number through reflection or some awesome API? Just like when exceptions occur, the line number gets printed out i

相关标签:
5条回答
  • 2020-12-14 01:08

    I was able to use the Thread.currentThread().getStackTrace() method to create a set of functions that work together to produce the line number of the code that called the first method, like so:

    /** @return The line number of the code that ran this method
     * @author Brian_Entei */
    public static int getLineNumber() {
        return ___8drrd3148796d_Xaf();
    }
    
    /** This methods name is ridiculous on purpose to prevent any other method
     * names in the stack trace from potentially matching this one.
     * 
     * @return The line number of the code that called the method that called
     *         this method(Should only be called by getLineNumber()).
     * @author Brian_Entei */
    private static int ___8drrd3148796d_Xaf() {
        boolean thisOne = false;
        int thisOneCountDown = 1;
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        for(StackTraceElement element : elements) {
            String methodName = element.getMethodName();
            int lineNum = element.getLineNumber();
            if(thisOne && (thisOneCountDown == 0)) {
                return lineNum;
            } else if(thisOne) {
                thisOneCountDown--;
            }
            if(methodName.equals("___8drrd3148796d_Xaf")) {
                thisOne = true;
            }
        }
        return -1;
    }
    

    Hope this helps! I put these in a utility class so that they are out of the way, but still easily accessible. The second method is private to prevent any other method other than the first method from calling it so that it always works correctly.

    0 讨论(0)
  • 2020-12-14 01:08

    Starting from JDK9 you can use the StackWalker. This gave me around a 50% of speed increase over using getStackTrace().

    int get_line_number() {
        return StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES).walk(
          (s) -> s.skip(1).findFirst()).get().getLineNumber();
    }
    

    My stream could be done better but I have no experience with it, and I really don't like streams in general, so feel free to edit my post to improve this part.

    0 讨论(0)
  • 2020-12-14 01:09

    You can create a Throwable and use its StackTraceElements:

      System.err.println(new Throwable().getStackTrace()[0].getLineNumber());
    

    As @Joachim said, you can also use Thread.getStackTrace(), e.g. like

      System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber());
    

    Be aware that the second approach returns a somewhat different array - you need to use the array element with index 1 to get the current line number, since it includes the call to getStackTrace() itself as the first element.

    Also note the comments about Logging and performance from @Joachim's answer.

    0 讨论(0)
  • 2020-12-14 01:23

    First of all: If anything, then the logging pattern (or layouter, or whatever your logging framework calls that part) should do this. The logger call in your code should only write the actual business information. Information about the where should be added by the logger.

    Next: getting that kind of operation is expensive (in terms of time), because Java is not optimized for this. At runtime, the JVM need to inspect its state, load/parse debug information and find the line number corresponding to a given instruction. That's why this kind of information is usually just given when an exception occurs (in which case we already have a problem and know that the time spent will usually be worth it).

    And last but not least: if for some reason you need that information on your own, you can use Thread.getStackTrace() and inspect the second StackTraceElement on it.

    0 讨论(0)
  • 2020-12-14 01:24

    One can also get the Exception line number using following snippet. Use following util method in your util class.

     public static int getExceptionLineNumber(Exception e, String methodNameExp) 
     {
        StackTraceElement ele = Arrays.stream(e.getStackTrace()).filter(o -> o.getMethodName().equals(methodNameExp)).findAny().orElse(null);
        if(ele != null){
            return ele.getLineNumber();
        }
        return -1;
     }
    

    From catch block you can call like below :

    catch (Exception e){
            logger.info("Exception line number "+ Util.getExceptionLineNumber(e, new Object(){}.getClass().getEnclosingMethod().getName()));
        }
    

    Hope this works! :)

    0 讨论(0)
提交回复
热议问题