Java: простой способ передачи метода в качестве параметра [duplicate]

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
328
задан Jeroen Vannevel 8 February 2014 в 19:55
поделиться

13 ответов

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()

Согласно Javadocs:

Последний элемент массива представляет собой нижнюю часть стека, которая является наименее недавним вызовом метода в последовательности.

A StackTraceElement имеет getClassName(), getFileName(), getLineNumber() и getMethodName().

Вам нужно будет поэкспериментировать, чтобы определить, какой индекс вы хотите (вероятно, stackTraceElements[1] или [2]).

366
ответ дан towi 17 August 2018 в 17:42
поделиться
  • 1
    Я должен отметить, что getStackTrace () все еще создает исключение, поэтому это не очень быстро - просто удобнее. – Michael Myers♦ 7 January 2009 в 19:08
  • 2
    Обратите внимание, что этот метод не даст вам вызывающего абонента, а только тип вызывающего . У вас не будет ссылки на объект, вызывающий ваш метод. – Joachim Sauer 7 January 2009 в 19:30
  • 3
    Просто сторона примечания, но на 1.5 JVM Thread.currentThread (). GetStackTrace () кажется намного медленнее, чем создание нового Exception () (примерно в 3 раза медленнее). Но, как уже отмечалось, вы все равно не должны использовать такой код в критичной для производительности области. ;) 1,6 JVM только кажется на ~ 10% медленнее, и, как заявила Software Monkey, она выражает намерение лучше, чем «новое исключение», путь. – GaZ 7 July 2009 в 15:42
  • 4
    @Eelco Thread.currentThread () дешево. Thread.getStackTrace () дорого, потому что, в отличие от Throwable.fillInStackTrace (), нет гарантии, что метод вызывается тем же потоком, который он исследует, поэтому JVM должен создать «safepoint», - блокировка кучи и стопки. См. Этот отчет об ошибке: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302 – David Moles 9 December 2011 в 01:30
  • 5
    @JoachimSauer знаете ли вы способ получить ссылку на объект, вызывающий метод? – jophde 19 January 2015 в 23:31

Java 9 - JEP 259: API-интерфейс стека

JEP 259 предоставляет эффективный стандартный API для стекирования, который позволяет легко фильтровать и ленивый доступ к информации в стеках. Перед API Stack-Walking обычными способами доступа к фреймам стека были:

Throwable::getStackTrace и Thread::getStackTrace возвращать массив из StackTraceElement объектов, которые содержат имя класса и имя метода каждого Элемент stack-trace.

SecurityManager::getClassContext - защищенный метод, который позволяет подклассу SecurityManager обращаться к контексту класса.

JDK-internal sun.reflect.Reflection::getCallerClass метод, который вы должны 't use anyway

Использование этих API обычно неэффективно:

Эти API требуют, чтобы виртуальная машина охотно захватывала моментальный снимок всего стека, и они возвращаются информация, представляющая весь стек. Невозможно избежать затрат на изучение всех кадров, если вызывающий объект интересуется только несколькими кадрами в стеке.

Чтобы найти класс непосредственного вызывающего, сначала получите a StackWalker:

StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

Затем либо вызовите getCallerClass():

Class<?> callerClass = walker.getCallerClass();

, либо walk StackFrame s и получите первое предыдущее StackFrame :

walker.walk(frames -> frames.map(StackWalker.StackFrame::getDeclaringClass).skip(1).findFirst());
11
ответ дан Ali Dehghani 17 August 2018 в 17:42
поделиться

Мне нравится new Exception("some message to find the exception easier").printStackTrace() больше.

-1
ответ дан Ali Zeynali 17 August 2018 в 17:42
поделиться
  • 1
    так что вы предлагаете, напечатайте трассировку стека на stdout, как вы показали, проанализируйте стандартную версию и попытайтесь найти вызывающего? – Stealth Rabbi 8 May 2018 в 22:22
private void parseExceptionContents(
      final Exception exception,
      final OutputStream out)
   {
      final StackTraceElement[] stackTrace = exception.getStackTrace();
      int index = 0;
      for (StackTraceElement element : stackTrace)
      {
         final String exceptionMsg =
              "Exception thrown from " + element.getMethodName()
            + " in class " + element.getClassName() + " [on line number "
            + element.getLineNumber() + " of file " + element.getFileName() + "]";
         try
         {
            out.write((headerLine + newLine).getBytes());
            out.write((headerTitlePortion + index++ + newLine).getBytes() );
            out.write((headerLine + newLine).getBytes());
            out.write((exceptionMsg + newLine + newLine).getBytes());
            out.write(
               ("Exception.toString: " + element.toString() + newLine).getBytes());
         }
         catch (IOException ioEx)
         {
            System.err.println(
                 "IOException encountered while trying to write "
               + "StackTraceElement data to provided OutputStream.\n"
               + ioEx.getMessage() );
         }
      }
   }
2
ответ дан AZ_ 17 August 2018 в 17:42
поделиться

Я сделал это раньше. Вы можете просто создать новое исключение и захватить трассировку стека, не бросая его, а затем проверить трассировку стека. Как сказал другой ответ, это очень дорого - не делайте этого в трудном цикле.

Я сделал это раньше для утилиты регистрации в приложении, где производительность не имеет большого значения ( Производительность редко имеет значение вообще, на самом деле - пока вы показываете результат на такое действие, например, быстро нажимаете кнопку).

До того, как вы смогли получить трассировку стека, исключения имели только .printStackTrace (), поэтому мне пришлось перенаправить System.out на поток моего собственного творения, затем (новый Exception ()). printStackTrace ( ); Перенаправить System.out назад и проанализировать поток. Интересный материал.

6
ответ дан Bill K 17 August 2018 в 17:42
поделиться
  • 1
    Круто; вам не нужно бросать его? – krosenvold 7 January 2009 в 19:00
  • 2
    Нет, по крайней мере, так я помню это, я не делал этого через несколько лет, но я уверен, что появление исключения - это просто создание объекта, а исключение ничего не делает, кроме как передать это в предложение catch (). – Bill K 7 January 2009 в 19:05
  • 3
    Ухоженная. Я был склонен бросить его, чтобы имитировать фактическое исключение. – Sathish 7 January 2009 в 19:13
  • 4
    Нет, поскольку Java 5 существует метод Thread, чтобы получить текущий стек как массив StackTraceElements; это все еще не дешево, но дешевле старого решения для разбора исключений. – Lawrence Dol 8 January 2009 в 09:40
  • 5
    @Software Monkey Хотя я уверен, что это более уместно, что заставляет вас сказать, что это дешевле? Я бы предположил, что будет использоваться тот же механизм, а если нет, зачем делать медленнее, когда он делает то же самое? – Bill K 8 January 2009 в 18:11

Альтернативное решение можно найти в комментарии к этому запросу для улучшения . Он использует метод getClassContext() пользовательского SecurityManager и, кажется, быстрее, чем метод трассировки стека.

Следующая программа проверяет скорость различных предложенных методов (наиболее интересный бит находится в внутренний класс SecurityManagerMethod):

/**
 * Test the speed of various methods for getting the caller class name
 */
public class TestGetCallerClassName {

  /**
   * Abstract class for testing different methods of getting the caller class name
   */
  private static abstract class GetCallerClassNameMethod {
      public abstract String getCallerClassName(int callStackDepth);
      public abstract String getMethodName();
  }

  /**
   * Uses the internal Reflection class
   */
  private static class ReflectionMethod extends GetCallerClassNameMethod {
      public String getCallerClassName(int callStackDepth) {
          return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
      }

      public String getMethodName() {
          return "Reflection";
      }
  }

  /**
   * Get a stack trace from the current thread
   */
  private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Current Thread StackTrace";
      }
  }

  /**
   * Get a stack trace from a new Throwable
   */
  private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {

      public String getCallerClassName(int callStackDepth) {
          return new Throwable().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Throwable StackTrace";
      }
  }

  /**
   * Use the SecurityManager.getClassContext()
   */
  private static class SecurityManagerMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return mySecurityManager.getCallerClassName(callStackDepth);
      }

      public String getMethodName() {
          return "SecurityManager";
      }

      /** 
       * A custom security manager that exposes the getClassContext() information
       */
      static class MySecurityManager extends SecurityManager {
          public String getCallerClassName(int callStackDepth) {
              return getClassContext()[callStackDepth].getName();
          }
      }

      private final static MySecurityManager mySecurityManager =
          new MySecurityManager();
  }

  /**
   * Test all four methods
   */
  public static void main(String[] args) {
      testMethod(new ReflectionMethod());
      testMethod(new ThreadStackTraceMethod());
      testMethod(new ThrowableStackTraceMethod());
      testMethod(new SecurityManagerMethod());
  }

  private static void testMethod(GetCallerClassNameMethod method) {
      long startTime = System.nanoTime();
      String className = null;
      for (int i = 0; i < 1000000; i++) {
          className = method.getCallerClassName(2);
      }
      printElapsedTime(method.getMethodName(), startTime);
  }

  private static void printElapsedTime(String title, long startTime) {
      System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
  }
}

Пример вывода с моего 2,4 ГГц Intel Core 2 Duo MacBook с поддержкой Java 1.6.0_17:

Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.

Внутреннее отражение метод много быстрее других. Получение трассировки стека из вновь созданного Throwable происходит быстрее, чем получение его от текущего Thread. И среди невнутренних способов поиска класса вызывающего абонента пользовательский SecurityManager кажется самым быстрым.

Update

Как говорит Льюми в этот комментарий метод sun.reflect.Reflection.getCallerClass() по умолчанию отключен в обновлении 40 Java 7 и полностью удален в Java 8. Подробнее об этом читайте в этой проблеме в базе данных ошибок Java .

Обновление 2

Как заметил zammbi, Oracle был вынужден вернуться из изменения , который удалил sun.reflect.Reflection.getCallerClass().

Обновление 3

Через 3 года: обновление времени с использованием текущей JVM.

> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.
199
ответ дан Community 17 August 2018 в 17:42
поделиться
  • 1
    Да, похоже. Но обратите внимание, что тайминги, которые я даю в примере, - это миллион звонков, поэтому в зависимости от того, как вы это используете, это может быть не проблема. – Johan Kaving 27 June 2012 в 12:09
  • 2
    Для меня удаление отражения от моего проекта привело к увеличению скорости в 10 раз. – Kevin Parker 27 June 2012 в 15:20
  • 3
    Да, отражение вообще медленное (см., Например, stackoverflow.com/questions/435553/java-reflection-performance ), но в этом конкретном случае используется внутренний sun.reflect.Reflection класс является самым быстрым. – Johan Kaving 28 June 2012 в 13:39
  • 4
    На самом деле это не нужно. Вы можете проверить это, изменив приведенный выше код, чтобы напечатать возвращаемое имя класса (и я предлагаю уменьшить количество циклов до 1). Вы увидите, что все методы возвращают одно имя класса - TestGetCallerClassName. – Johan Kaving 7 August 2012 в 07:07
  • 5
    getCallerClass устарел и будет удален в 7u40 .. sad :( – lyomi 5 August 2013 в 03:02

Похоже, вы пытаетесь избежать передачи ссылки на this в метод. Передача this намного лучше, чем поиск вызывающего абонента по текущей трассировке стека. Рефакторинг для более OO-дизайна еще лучше. Вам не нужно знать вызывающего абонента. При необходимости передайте объект обратного вызова.

34
ответ дан Craig P. Motlin 17 August 2018 в 17:42
поделиться
  • 1
    ++ Знание вызывающего абонента слишком много информации. Если вам нужно, вы можете пройти интерфейс, но есть хороший шанс, что необходим большой рефакторинг. @satish должен опубликовать свой код и дать нам немного удовольствия с ним :) – Bill K 7 January 2009 в 19:19
  • 2
    Имеются веские причины для этого. У меня было несколько случаев, когда я нашел его полезным во время тестирования, например. – Eelco 2 February 2010 в 06:23
  • 3
    @chillenious Я знаю :) Я сам сделал это, чтобы создать метод, подобный LoggerFactory.getLogger(MyClass.class), где мне не пришлось проходить в литературе класса. Это все еще редко бывает правильным. – Craig P. Motlin 2 February 2010 в 16:05
  • 4
    Это хороший совет в целом, но он не отвечает на вопрос. – Navin 15 November 2013 в 22:38
  • 5
    Конкретным примером того, когда можно было бы принять правильное дизайнерское решение для получения информации о вызывающем абоненте, является реализация интерфейса .NET INotifyPropertyChanged. Хотя этот конкретный пример не в Java, та же проблема может проявляться при попытке моделировать поля / геттеры как строки для Reflection. – Chris Kerekes 15 January 2016 в 18:13
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

class DBConnection {
    String createdBy = null;

    DBConnection(Throwable whoCreatedMe) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        whoCreatedMe.printStackTrace(pw);
        try {
            createdBy = os.toString();
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable(
                "Connection created from DBConnectionManager");
        DBConnection conn = new DBConnection(createdBy);
        System.out.println(conn.createdBy);
    }
}

ИЛИ

public static interface ICallback<T> { T doOperation(); }


public class TestCallerOfMethod {

    public static <T> T callTwo(final ICallback<T> c){
        // Pass the object created at callee to the caller
        // From the passed object we can get; what is the callee name like below.
        System.out.println(c.getClass().getEnclosingMethod().getName());
        return c.doOperation();
    }

    public static boolean callOne(){
        ICallback callBackInstance = new ICallback(Boolean){
            @Override
            public Boolean doOperation() 
            {
                return true;
            }
        };
        return callTwo(callBackInstance);
    }

    public static void main(String[] args) {
         callOne();
    }
}
1
ответ дан Kanagavelu Sugumar 17 August 2018 в 17:42
поделиться

Этот метод делает то же самое, но немного более просто и, возможно, немного более результативно, и в случае, если вы используете отражение, он автоматически пропускает эти кадры. Единственная проблема заключается в том, что он может отсутствовать в JVM, отличном от Sun, хотя он включен в классы времени выполнения JRockit 1.4 -> 1.6. (Точка не является классом public ).

sun.reflect.Reflection

    /** Returns the class of the method <code>realFramesToSkip</code>
        frames up the stack (zero-based), ignoring frames associated
        with java.lang.reflect.Method.invoke() and its implementation.
        The first frame is that associated with this method, so
        <code>getCallerClass(0)</code> returns the Class object for
        sun.reflect.Reflection. Frames associated with
        java.lang.reflect.Method.invoke() and its implementation are
        completely ignored and do not count toward the number of "real"
        frames skipped. */
    public static native Class getCallerClass(int realFramesToSkip);

Насколько известно значение realFramesToSkip, версии Sun 1.5 и 1.6 VM java.lang.System, существует метод защиты пакетов, называемый getCallerClass (), который вызывает sun.reflect.Reflection.getCallerClass(3), но в моем классе вспомогательной утилиты, который я использовал 4, поскольку есть добавленный фрейм вызова вспомогательного класса.

10
ответ дан Nicholas 17 August 2018 в 17:42
поделиться
  • 1
    Использование классов реализации JVM - это плохая идея really . – Lawrence Dol 8 January 2009 в 09:42
  • 2
    Отметил. Я указал, что это не открытый класс, а защищенный метод getCallerClass () в java.lang.System присутствует во всех 1.5 + VM, на которые я смотрел, включая IBM, JRockit и Sun, но ваше утверждение носит консервативный характер , – Nicholas 8 January 2009 в 20:05
  • 3
    @Software Monkey, как обычно, «все зависит». Делая что-то подобное, чтобы помочь в отладке или протоколировании протоколов, особенно если это никогда не заканчивается производственным кодом, или если цель развертывания является строго ПК разработчика, вероятно, будет в порядке. Любой, кто все еще думает иначе, даже в таких случаях: вам нужно будет фактически объяснить « действительно плохую идею & quot; рассуждая лучше, чем просто сказать, что это плохо ... – user 17 March 2013 в 23:29
  • 4
    Кроме того, по аналогичной логике вы также можете утверждать, что в любое время, когда вы используете функцию Hibernate, которая не поддерживает JPA, это всегда «плохая идея» действительно . Или, если вы собираетесь использовать функции, специфичные для Oracle, которые недоступны в других базах данных, это плохая идея & quot; действительно . Уверен, что это более безопасное мышление и определенно хороший совет для определенных целей, но автоматически отбрасывает полезные инструменты только потому, что он не будет работать с конфигурацией программного обеспечения, которую вы, а .. вообще не используете ? Это немного негибкий и немного глупый. – user 17 March 2013 в 23:39
  • 5
    Неохраняемое использование специфических для поставщика классов будет представлять более высокую вероятность возникновения проблем, но нужно определить путь к грациозному ухудшению, если рассматриваемый класс отсутствует (или по какой-либо причине запрещен). На самом деле политика отказа от использования каких-либо специфических для вендоров классов, по-моему, немного наивна. Сотрясайте исходный код некоторых библиотек, которые вы используете на производстве, и посмотрите, не делает ли это кто-либо из них. (возможно, sun.misc.Unsafe?) – Nicholas 25 June 2013 в 15:03

Oneliner:

Thread.currentThread().getStackTrace()[2].getMethodName()

Обратите внимание, что вам может потребоваться заменить 2 на 1.

8
ответ дан Nir Duan 17 August 2018 в 17:42
поделиться

Вот часть кода, который я сделал на основе подсказок, показанных в этом разделе. Надеюсь, что это поможет.

(Не стесняйтесь делать какие-либо предложения по улучшению этого кода, пожалуйста, скажите мне)

Счетчик:

public class InstanceCount{
    private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;


    public void count() {
        counterInstanceLog= new counterInstanceLog();
    if(counterInstanceLog.getIdHashCode() != 0){
    try {
        if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
         counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
    }

    counterInstanceLog.incrementCounter();

            instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
    }

    (...)
}

И объект :

public class CounterInstanceLog{
    private int idHashCode;
    private StackTraceElement[] arrayStackTraceElements;
    private int instanceCount;
    private String callerClassName;

    private StackTraceElement getProjectClasses(int depth) {
      if(depth< 10){
        getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
        if(getCallerClassName().startsWith("com.yourproject.model")){
            setStackTraceElements(Thread.currentThread().getStackTrace());
            setIdHashCode();
        return arrayStackTraceElements[depth];
        }
        //+2 because one new item are added to the stackflow
        return getProjectClasses(profundidade+2);           
      }else{
        return null;
      }
    }

    private void setIdHashCode() {
        if(getNomeClasse() != null){
            this.idHashCode = (getCallerClassName()).hashCode();
        }
    }

    public void incrementaContador() {
    this.instanceCount++;
}

    //getters and setters

    (...)



}
1
ответ дан Pmt 17 August 2018 в 17:42
поделиться

используйте этот метод: -

 StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
 stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
 System.out.println(e.getMethodName());

Вызывающий пример метода Код здесь: -

public class TestString {

    public static void main(String[] args) {
        TestString testString = new TestString();
        testString.doit1();
        testString.doit2();
        testString.doit3();
        testString.doit4();
    }

    public void doit() {
        StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
        System.out.println(e.getMethodName());
    }

    public void doit1() {
        doit();
    }

    public void doit2() {
        doit();
    }

    public void doit3() {
        doit();
    }

    public void doit4() {
        doit();
    }
}
1
ответ дан Reegan Miranda 17 August 2018 в 17:42
поделиться
     /**
       * Get the method name for a depth in call stack. <br />
       * Utility function
       * @param depth depth in the call stack (0 means current method, 1 means call method, ...)
       * @return method name
       */
      public static String getMethodName(final int depth)
      {
        final StackTraceElement[] ste = new Throwable().getStackTrace();

        //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
        return ste[ste.length - depth].getMethodName();
      }

Например, если вы попытаетесь получить линию метода вызова для цели отладки, вам нужно пройти мимо класса Utility, в котором вы кодируете эти статические методы: (старый код java1.4, только для иллюстрируют потенциальное использование StackTraceElement)

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
          * From the Stack Trace.
          * @return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
          */
        public static String getClassMethodLine()
        {
            return getClassMethodLine(null);
        }

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
          * Allows to get past a certain class.
          * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
          * @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
          */
        public static String getClassMethodLine(final Class aclass)
        {
            final StackTraceElement st = getCallingStackTraceElement(aclass);
            final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
            +")] <" + Thread.currentThread().getName() + ">: ";
            return amsg;
        }

     /**
       * Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
       * Stored in array of the callstack. <br />
       * Allows to get past a certain class.
       * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
       * @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
       * @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
       */
      public static StackTraceElement getCallingStackTraceElement(final Class aclass)
      {
        final Throwable           t         = new Throwable();
        final StackTraceElement[] ste       = t.getStackTrace();
        int index = 1;
        final int limit = ste.length;
        StackTraceElement   st        = ste[index];
        String              className = st.getClassName();
        boolean aclassfound = false;
        if(aclass == null)
        {
            aclassfound = true;
        }
        StackTraceElement   resst = null;
        while(index < limit)
        {
            if(shouldExamine(className, aclass) == true)
            {
                if(resst == null)
                {
                    resst = st;
                }
                if(aclassfound == true)
                {
                    final StackTraceElement ast = onClassfound(aclass, className, st);
                    if(ast != null)
                    {
                        resst = ast;
                        break;
                    }
                }
                else
                {
                    if(aclass != null && aclass.getName().equals(className) == true)
                    {
                        aclassfound = true;
                    }
                }
            }
            index = index + 1;
            st        = ste[index];
            className = st.getClassName();
        }
        if(resst == null) 
        {
            //Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies 
            throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
        }
        return resst;
      }

      static private boolean shouldExamine(String className, Class aclass)
      {
          final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
            ) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
          return res;
      }

      static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
      {
          StackTraceElement   resst = null;
          if(aclass != null && aclass.getName().equals(className) == false)
          {
              resst = st;
          }
          if(aclass == null)
          {
              resst = st;
          }
          return resst;
      }
7
ответ дан VonC 17 August 2018 в 17:42
поделиться
  • 1
    Мне нужно что-то, что работает с Java 1.4, и этот ответ был очень полезен! Спасибо! – RGO 7 March 2014 в 08:03
Другие вопросы по тегам:

Похожие вопросы: