Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как узнать из какого метода позвался, текущий метод (т.е. как узнать caller'а) 
:(
    Опции темы
Royan
Дата 18.5.2005, 13:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



Всем привет,

Банальный вопрос, имеем
Код

pucblic void a1(){
    b();
}

pucblic void a2(){
    b();
}

pucblic void b(){
    /* Хочу узнать откуда позвался b() из a1() или a2() */
}


Такой вот вопрос. Сразу скажу решение, которое не хочется применять - это кинуть в b() exception и проанализировать стек, но это грубо, может можно более элегантно?


--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
batigoal
Дата 18.5.2005, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Мне кажется, в данном случае не кривого решения и не может быть. Лучше всего переделать код, чтобы он передавал в метод b ссылку на себя this.

Может, через рефлексию как-нибудь можно?


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
3,14
Дата 18.5.2005, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1614
Регистрация: 18.6.2004
Где: Н. Новгород

Репутация: 6
Всего: 24



Можно конечно воспользоваться Thread.dumpStack(), но лучше сделать так как советует Lamer George


--------------------
Может быть, это только мой бред,
Может быть, жизнь не так хороша,
Может быть, я не выйду на свет,
Но я летал, когда пела душа...
PM MAIL   Вверх
AntonSaburov
Дата 18.5.2005, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Я делал так - просто кидал эксепшн. Что-то вроде такого

Код

public class Test
{
  public static void main(String[] args)
  {
    Test t = new Test();
    t.show1();
    System.out.println("******************");
    t.show2();
  }

  public void show1()
  {
    show2();
  }

  public void show2()
  {
    try {
      throw new Exception("show2");
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
}

PM MAIL WWW ICQ   Вверх
batigoal
Дата 18.5.2005, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



AntonSaburov
Но ведь это не очень хорошо с точки зрения рефакторинга - имя метода поменяется, и строку придется парсить по-другому...



--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
AntonSaburov
Дата 18.5.2005, 16:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Зачем по-другому - формат ведь всегда стандартный. Ты просто печатаешь стэк. Можно его вообще получать стандартно через StackTraceElement. Там просто имена методов получают отдельным методом.

Код

public class Test
{
  public static void main(String[] args)
  {
    Test t = new Test();
    t.show1();
    System.out.println("******************");
    t.show2();
  }

  public void show1()
  {
    show2();
  }

  public void show2()
  {
    try {
      throw new Exception("show2");
    }
    catch(Exception e) {
      StackTraceElement[] assa = e.getStackTrace();
      for(int i=0; i<assa.length; i++) {
        System.out.println(assa[i].getMethodName());
      }
    }
  }
}

PM MAIL WWW ICQ   Вверх
batigoal
Дата 18.5.2005, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Ух ты, я и не знал про StackTraceElement.


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
Royan
Дата 18.5.2005, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



Признаюсь я смотрел в сторону этого класса, но угрожающий список параметров конструктора меня отпугнул, не знал, что его можно так просто использовать. Спасибо!


--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
Stampede
Дата 18.5.2005, 19:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Цитата(AntonSaburov @ 18.5.2005, 16:18)
Я делал так - просто кидал эксепшн


На самом деле кидать эксепшен необязательно - достаточно всего лишь создать объект типа Exception (ну или Throwable - кому как нравится). Чтобы узнать имя вызвавшего метода, получаем массив элементов StackTraceElement и ссылаемся на элемент с индексом 1 (нулевой элемент указывает на текущий метод).

Код

    public void testTrace()
    {
        Exception e = new Exception();
        StackTraceElement[] trace = e.getStackTrace();
        for (int i = 0, n = trace.length; i < n; i++)
        {
            System.out.println("Method: " + trace[i].getMethodName() + " at line " +
                        trace[i].getLineNumber() + " in " + trace[i].getClassName());
        }
    }


Если быть точнее, то кидать эксепшен для целей получения стека не только необязательно, но и просто вредно - например, из соображений производительности, поскольку отработка цикла try-catch отъедает на порядок большее количество тактов.

Кстати, до версии 1.4 получить стек можно было только в текстовом виде, и когда я писал свой асинхронный логгер в до- log4j эру, то мне приходилось полагаться на формат вывода printStackTrace() и парсить его до нужных элементов. Что вызывало у меня легкое чувство нервозности, потому как никогда не знаешь, какие улучшения в плане формата вывода могут взбрести в голову отцам-основателям в следующей верии Java.

Но теперь жить стало лучше, жить стало веселей - спасибо партии за это! smile

PM WWW   Вверх
Domestic Cat
Дата 18.5.2005, 19:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Stampede @ 18.5.2005, 10:17)
на порядок большее количество тактов.

На порядок - врядли, несколько гото и все.


--------------------

PM   Вверх
Stampede
Дата 18.5.2005, 22:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Цитата(Domestic @ 18.5.2005, 19:21)
На порядок - врядли, несколько гото и все


Не согласен. Несколько гото - это в случае нормального хода выполнения программы, когда исключений не происходит. В данном же примере предлагалось использовать try/catch на регулярной основе, для выуживания информации о вызывающем методе - и в этом случае мы можем говорить именно о серъезных потерях производительности. Причем потери эти совершенно неоправданные, на что я и указал в своем посте.

Если говорить о конкретных цифрах, то вот я тут прилагаю отчет, сгенерированный маленьким тестовым апплетом, взятом из статьи в JavaWorld:

Код

Benchmark tests:  [mem=8082184/11202560]
Estimated time: 1:05 (tests 0:57)

=== Mixed Benchmark ===
for ( ; i < local; i++)                            3192 ps
for ( ; --i >= 0; )                                4701 ps
local int x = x                                     908 ps
local int array[0] = array[0]                      2762 ps
static int x = x                                   1035 ps
instance int x = x                                 1984 ps
static method() {return 0;}                        -124 ps
instance int method() {return 0;}                   383 ps
instance synchronized method() {return 0;}        20343 ps
local byte += byte                                15455 ps
local short += short                                982 ps
local int += int                                   1002 ps
local long += long                                 5094 ps
local float += float                              12964 ps
local double += double                            12989 ps
Subclass s = (Subclass) superclass                 2312 ps
Interface i = (Interface) object                   2193 ps
new Object()                                      16937 ps
Throw and catch new Exception()                 4175320 ps
=== Mixed TOTAL:                                4280432 ps
*** done: 1:12 (tests 1:10) ***


Особое внимание прошу обратить на эту строчку:

Throw and catch new Exception() 4175320 ps

А вот что имеет сказать по данному поводу уважаемый мной Билл Веннерс:

Цитата

So the VM has to do the same thing as it executes along whether or not you have the try/catch there. It is only if the exception is actually thrown that the performance hit comes. To get an idea how expensive a throw/catch is, check out: http://www.javaworld.com/javaworld/jw-04-1...rk_Results.html

Источник: http://www.artima.com/legacy/design/except...essages/20.html


Резюме: никогда не используйте try/catch как средство управления логикой нормального хода выполнения программы. smile

PM WWW   Вверх
Domestic Cat
Дата 18.5.2005, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172



Цитата(Stampede @ 18.5.2005, 13:14)
Throw and catch new Exception() 4175320 ps


Дык это ведь не только логика ловли иксепшна, это и создание нового объекта что много времени занимает, а в данном случае он по-любому создается.
Если по байткоду судить - ничего особо серьезного кетч не даст... Но конечно без него лучше.


--------------------

PM   Вверх
Stampede
Дата 18.5.2005, 23:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Чудеса в решете какие-то. Взял сейчас, не поленился и написал маленький тест:

Код

public class Test
{
    public static void main(String[] args)
    {
        Test test = new Test();

        int CNT = 1000;

        long t0 = System.currentTimeMillis();
        for (int i = 0; i < CNT; i++)
        {
            test.testThrow();
        }

        long t1 = System.currentTimeMillis();
        for (int i = 0; i < CNT; i++)
        {
            test.testNoThrow();
        }

        long t2 = System.currentTimeMillis();
        System.out.println("Test times are:");
        System.out.println("  when throwing exceptions:     " + (t1 - t0) + " ms");
        System.out.println("  when not throwing exceptions: " + (t2 - t1) + " ms");
    }

    private void testThrow()
    {
        try
        {
            throw new Exception();
        }
        catch (Exception e)
        {
            String s = e.getStackTrace()[1].getMethodName();
            System.out.println(s);
        }
    }

    private void testNoThrow()
    {
        Exception e = new Exception();
        String s = e.getStackTrace()[1].getMethodName();
        System.out.println(s);
    }


Получил вот такие результаты:

Код

Test times are:
  when throwing exceptions:     203 ms
  when not throwing exceptions: 94 ms


Расхождение оказалось совсем небольшим, так что я решил попробовать исключить из эксперимента время вывода на консоль, чтобы получить разницу, так сказать, в чистом виде. С этой целью я закомментировал в обоих методах строку с System.out.println() и запустил еще раз. Что бы вы думали?

Код

Test times are:
  when throwing exceptions:     16 ms
  when not throwing exceptions: 15 ms


То есть практически одинаковое время! Потом я еще маленько поэкспериментировал и пришел в выводу, что единственный и главный накладной расход при возникновении исключения - это создание собственно объекта Exception, а действиями по разруливанию try/catch можно действительно пренебречь.

Этот факт не отменяет валидности моего (и не только моего) пойнта о том, что try/catch не должны использоваться для управления нормальной логикой, но вот применительно к случаю получения имени вызывающего метода - таки да, выбрасывание/ловля уже созданного исключения практически никакого дополнительного тормоза не привносит.

Хотя как можно объяснить тот факт, что в самом первом тесте (с выводом на консоль) время все-таки отличалось в два раза?

Цитата(Domestic @ 18.5.2005, 22:22)
Если по байткоду судить - ничего особо серьезного кетч не даст


Котъ, снимаю шляпу. Я по байткоду судить не умею, потому и чуть было не попал впросак. Забираю свои слова взад. Но Антону хочу сказать, что бросать/ловить исключение в его примере все равно не имело никакого смысла, даже если это и не повклекло за собой больших накладных расходов smile

Это сообщение отредактировал(а) Stampede - 18.5.2005, 23:43


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Domestic Cat
Дата 19.5.2005, 00:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5452
Регистрация: 3.5.2004
Где: Dallas, US

Репутация: 50
Всего: 172





Цитата(Stampede @ 18.5.2005, 14:36)
Я по байткоду судить не умею, потому и чуть было не попал впросак.


Там ничего сложного нет, я вот тут писал:
http://forum.vingrad.ru/index.php?showtopic=35748&st=0

А вот код для двух методов testNoThrow() и testThrow()
Код

//testThrow
       0        new java/lang/Exception
       3        dup
       4        invokespecial java/lang/Exception/<init>()V
       7        athrow
       8        astore_1
       9        aload_1
      10        invokevirtual java/lang/Exception/getStackTrace()[Ljava/lang/StackTraceElement;
      13        iconst_1
      14        aaload
      15        invokevirtual java/lang/StackTraceElement/getMethodName()Ljava/lang/String;
      18        astore_2
      19        getstatic java/lang/System/out Ljava/io/PrintStream;
      22        aload_2
      23        invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
      26        return

Код

//testNoThrow
   0        new java/lang/Exception
       3        dup
       4        invokespecial java/lang/Exception/<init>()V
       7        astore_1
       8        aload_1
       9        invokevirtual java/lang/Exception/getStackTrace()[Ljava/lang/StackTraceElement;
      12        iconst_1
      13        aaload
      14        invokevirtual java/lang/StackTraceElement/getMethodName()Ljava/lang/String;
      17        astore_2
      18        getstatic java/lang/System/out Ljava/io/PrintStream;
      21        aload_2
      22        invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
      25        return
 

Тут JVM все так оптимизировала, что разницы практически нет smile


--------------------

PM   Вверх
Stampede
Дата 19.5.2005, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Кстати, на сайте моего любимого Билла Веннерса можно увидеть работу сего байткода (ну, в чуть-чуть измененном виде) в анимированном, так сказать, виде:

Апплет Play Ball

А на этой страничке собраны ссылки на избранные главы из его книжки Inside The Java Virtual Machine, а также статьи, написанные им для колонки в Java World под названием Under The Hood (под капотом) - о различных аспектах внутреннего устройства JVM. Там же каталог апплетов, которые иллюстрируют работу JVM.

Вообще, Билл Веннерс - это один из самых толковых чуваков в Java индустрии. Если раньше не видели - категорически рекомендую.

Энджойте smile

PM WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0640 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.