Наконец блок всегда выполняется в Java?

Как указано в моем комментарии, utm.gif больше не используется. Google Analytics полностью переключилась на протокол измерений, и данные теперь отправляются в конечную точку для протокола измерения на google-analytics.com/collect. На самом деле это все равно возвращает прозрачный пиксель, поскольку вызов изображения с параметрами является методом завещания передачи информации через границы домена.

Теперь вы можете просто измерить протокол для реализации своего собственного трекера Google Analytics.

К quote myself :

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

Таким образом, самый простой пример для записи просмотра страницы будет выглядеть так:

www.google-analytics.com/collect/v= 1 & amp; tid = UA-XXXXY & amp; cid = 555 & amp; t = pageview & amp; dp =% 2Fmypage

blockquote>

Возможно, вы захотите добавить IP-адрес пользователей (будет анонимным ymized автоматически) и пользовательский агент.

Однако похоже, что вы предпочитаете использовать стандартный код Google Analytics для сбора данных и ретрансляции вызова отслеживания через собственный сервер. Хотя я не использовал следующее в производстве, я не вижу причин, почему это не сработает.

Сначала вам нужен файл analytics.js. Самостоятельный хостинг файла обескуражен, но данная причина заключается в том, что иногда код иногда обновляется Google, и если вы его размещаете самостоятельно, вы можете пропустить обновления. Это можно исправить, установив задание cron, которое регулярно загружает файл на ваш сервер, поэтому у вас всегда есть текущая версия.

Затем вы адаптируете функцию автозагрузки GA для загрузки кода с вашего собственного сервера :

  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.myserver.com/analytics.js','ga');

Теперь у вас есть код, но вызов отслеживания по-прежнему будет отправлен на сервер Analytics (т. е. в вашем случае он вообще не будет отправлен). Таким образом, вам необходимо перенаправить вызов через ваш сервер.

Чтобы это стало возможным, в Google (Universal) Analytics Code есть функция , называемая «задачи». Задачи - это функции внутри код отслеживания, в котором собирается вызов отслеживания.

Можно изменять задачи, используя функцию «set» объекта трекера, используя имя задачи как параметр и передавая функцию, которая перезаписывает / перегружает функция задачи.

Ниже приведен пример из документации Google (за исключением того, что я пропустил ту часть, где данные по-прежнему отправляются в Google - вам это не нужно в данный момент):

ga('create', 'UA-XXXXX-Y', 'auto');

ga(function(tracker) {

  tracker.set('sendHitTask', function(model) {
    var payLoad = model.get('hitPayload');
    var gifRequest = new XMLHttpRequest();
    var gifPath = "/__ua.gif";
    gifRequest.open('get', gifPath + '?' + payLoad, true);
    gifRequest.send();
  });
});

ga('send', 'pageview');   

Теперь это отправляет данные в файл с именем __ua.gif на вашем собственном сервере (если вам нужно отправить данные по междоменному домену, вы можете просто сделать var ua = new Image; ua.src = gifPath + '?' + payLoad для создания запроса на изображение.

Параметр модели для функции sendHitTask содержит (помимо большого количества служебных данных) полезную нагрузку, то есть собранную строку запроса t hat содержит данные аналитики. Затем вы можете создать свой _ua.gif скрипт, который проксирует запрос на google-analytics.com/collect.

В этот момент пользовательский агент будет вашим сценарием, а IP-адрес будет вашим адресом, поэтому вам нужно включить & amp; uip (переопределение пользовательского IP-адреса) и & amp; ua (переопределить агент пользователя) параметры ( https://groups.google.com/forum/#!msg/google-analytics-measurement-protocol/8TAp7_I1uTk/KNjI5IGwT58J ) для получения гео- и технической информации.

Если вы чувствуете себя более предприимчивым, вы можете переопределить buildHitTask вместо этого и попробовать и добавить дополнительные параметры там (больше хлопот, вероятно, так как вам нужно будет получить IP-адрес откуда-то).

Дополнительный параметр см. в ссылке для analytics.js и протокола измерения .

2277
задан Matthias Braun 23 April 2019 в 04:04
поделиться

20 ответов

Да, finally будет назван после выполнения try или catch блоки кода.

Единственные времена finally не будет назван:

  1. Если Вы вызываете System.exit()
  2. Если Вы вызываете Runtime.getRuntime().halt(exitStatus)
  3. Если JVM отказывает сначала
  4. Если JVM достигает бесконечного цикла (или некоторый другой непрерываемый, не завершающийся оператор) в try или catch блок
  5. Если ОС насильственно завершает процесс JVM; например, kill -9 <pid> на UNIX
  6. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС, и так далее
  7. Если finally блок будет выполняемым потоком демона и всем другим выходом потоков недемона прежде finally назван
2558
ответ дан 22 November 2019 в 19:55
поделиться

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

7
ответ дан 22 November 2019 в 19:55
поделиться

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

7
ответ дан 22 November 2019 в 19:55
поделиться

Наконец блок всегда выполняется, если нет аварийное завершение программы, или следующее из катастрофического отказа JVM или от вызова до System.exit(0).

Вдобавок ко всему, любое значение, возвращенное из наконец блока, будет переопределять значение, возвращенное до выполнения наконец блок, так остерегаться проверки всех точек выхода при использовании попытки наконец.

18
ответ дан 22 November 2019 в 19:55
поделиться

Я попробовал вышеупомянутый пример небольшой модификацией -

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Вышеупомянутые выводы кода:

наконец возврат козырей.
2

Это вызвано тем, что когда return i; выполняется i имеет значение 2. После этого finally блок выполняется, где 12 присваивают i и затем System.out выполняется.

После выполнения finally заблокируйтесь try блок возвращается 2, вместо того, чтобы возвратиться 12, потому что этот оператор возврата не выполняется снова.

При отладке этого кода в Eclipse затем, Вы получите чувство что после выполнения System.out из finally заблокируйтесь return оператор try блок выполняется снова. Но дело обстоит не так. Это просто возвращает значение 2.

114
ответ дан 22 November 2019 в 19:55
поделиться

Логический способ думать об этом:

  1. Код поместил в наконец, блок должен быть выполнен, что происходит в блоке попытки
  2. Таким образом, если код в блоке попытки пытается возвратить значение или выдать исключение, объект положен 'на полку' до наконец, блок может выполниться
  3. Поскольку код в наконец блок имеет (по определению) высокий приоритет, он может возвратить или бросить то, что он любит. В этом случае что-нибудь 'на полке' отбрасывается.
  4. Единственное исключение к этому - то, если VM закрывается полностью во время блока попытки, например, 'System.exit'
40
ответ дан 22 November 2019 в 19:55
поделиться

наконец всегда выполняется, если нет аварийное завершение программы (как вызов System.exit (0)..). таким образом Ваш sysout будет распечатан

20
ответ дан 22 November 2019 в 19:55
поделиться

Также возврат в наконец выбросит любое исключение. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

19
ответ дан 22 November 2019 в 19:55
поделиться

Кроме того, хотя это - плохая практика, если будет оператор возврата в наконец блок, то это превзойдет любой другой возврат из регулярного блока. Таким образом, следующий блок возвратил бы false:

try { return true; } finally { return false; }

То же самое с выдаванием исключения от наконец блока.

374
ответ дан 22 November 2019 в 19:55
поделиться

Да это назовут. Это - смысл наличия наконец ключевое слово. Если выпрыгивание из блока попытки/выгоды могло просто пропустить наконец блок, это совпало с помещением System.out.println вне попытки/выгоды.

9
ответ дан 22 November 2019 в 19:55
поделиться

Пример кода:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("finally trumps return.");
    }
}

Вывод:

finally trumps return. 
0
532
ответ дан 22 November 2019 в 19:55
поделиться

В дополнение к другим ответам важно указать, что 'finally' имеет право переопределить любое исключение / возвращаемое значение блоком try..catch. Например, следующий код возвращает 12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

Аналогично, следующий метод не генерирует исключение:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

Хотя следующий метод выдает его:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}
155
ответ дан 22 November 2019 в 19:55
поделиться

Наконец, всегда запускается, в этом вся суть, просто потому, что это появляется в коде после возврата, не означает, что это реализовано именно так. Среда выполнения Java отвечает за запуск этого кода при выходе из блока try .

Например, если у вас есть следующее:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Среда выполнения сгенерирует что-то вроде этого:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Если возникает неперехваченное исключение, запускается блок finally , и исключение продолжает распространяться.

13
ответ дан 22 November 2019 в 19:55
поделиться

В этом и заключается вся идея блока finally. Он позволяет вам убедиться, что вы выполнили очистку, которая в противном случае могла бы быть пропущена из-за возврата, среди прочего, конечно.

Finally вызывается независимо от того, что происходит в блоке try (если только вы не вызываете System.exit(int) или виртуальная машина Java не вылетает по какой-то другой причине).

54
ответ дан 22 November 2019 в 19:55
поделиться

Потому что блок finally будет вызываться всегда, пока вы не вызовете System.exit() (или поток не завершится).

10
ответ дан 22 November 2019 в 19:55
поделиться

Вот официальные слова из спецификации языка Java.

14.20.2. Выполнение try-finally и try-catch-finally

Оператор try с блоком finally выполняется первым путем выполнения блока try . Тогда есть выбор:

  • Если выполнение блока try завершается нормально, [...]
  • Если выполнение блока try завершается внезапно из-за ошибки throw значения V , [...]
  • Если выполнение блока try завершается внезапно по любой другой причине R , затем выполняется блок finally . Затем есть выбор:
    • Если блок finally завершается нормально, то оператор try завершается внезапно по причине R .
    • Если блок finally завершается внезапно по причине S , то оператор try завершается внезапно по причине S ( и причина R отброшена ).

Спецификация для return фактически делает это явным:

JLS 14.17 Заявление return

 ReturnStatement:
return Expression (опт);

Оператор return без Выражение пытается передать управление вызывающей стороне метода или конструктора, который его содержит.

Оператор return с выражением пытается передать управление вызывающей стороне метода, который его содержит; значение Выражения становится значением вызова метода.

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

252
ответ дан 22 November 2019 в 19:55
поделиться

Это потому, что вы присвоили i значение 12, но не вернули значение i функции. Правильный код выглядит следующим образом:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
11
ответ дан 22 November 2019 в 19:55
поделиться

Вот некоторые условия, которые могут обойти наконец блок:

  1. , Если JVM выходит, в то время как код попытки или выгоды выполняется, затем наконец, блок не может выполниться. Больше на учебное руководство
  2. солнца Нормальное Завершение работы - это происходит или когда последний поток недемона выходит ИЛИ когда Runtime.exit () ( некоторый хороший блог ). Когда поток выходит, JVM выполняет материально-технические ресурсы выполнения потоков, и если единственные потоки, которые оставляют, являются потоками демона, это инициирует организованное завершение работы. Когда JVM останавливается, от любых остающихся потоков демона отказываются наконец, блоки не выполняются, стеки не раскручены, JVM просто выходит. Потоки демона должны использоваться экономно, от немногих операций обработки можно безопасно отказаться в любое время без очистки. В частности, опасно использовать потоки демона для задач, которые могли бы выполнить любой вид ввода-вывода. Потоки демона лучше всего сохраняются для задач "обслуживания", таких как фоновый поток, который периодически удаляет истекшие записи из кэша в оперативной памяти ( источник )

Последний пример выходов потока недемона:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

Вывод:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
1
ответ дан 22 November 2019 в 19:55
поделиться

Потому что финал всегда вызывается в любых случаях, которые у вас есть. У вас нет исключения, оно по-прежнему вызывается, перехватывает исключение, оно по-прежнему называется

3
ответ дан 22 November 2019 в 19:55
поделиться

Рассмотрим это в нормальном ходе выполнения (т.е. без выброса исключения): если метод не является 'void', то он всегда явно возвращает что-то, но в конечном итоге всегда выполняется

3
ответ дан 22 November 2019 в 19:55
поделиться
Другие вопросы по тегам:

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