Использование try-finally для выполнения операторов после возврата - PullRequest
0 голосов
/ 02 июля 2018

Рассмотрим следующий код:

Foo result = array[index];
index = (index + 1) % array.length;
return result;

Для выполнения некоторых финальных действий требуется дополнительная переменная. Имеет ли смысл написать это как:

try {
    return array[index];
} finally {
    index = (index + 1) % array.length;
}

или это повлияет на производительность? Обычно это считается хорошей / плохой практикой, и если да, то почему?

(В примере предполагается, что index является допустимым индексом для array, и код не будет выдавать ArrayIndexOutOfBoundsException)

Редактировать: вопрос не в необходимости использования try-finally, а в том, чтобы получить какой-либо выигрыш или потерю в производительности, которую я получаю, решив это сделать. Без этого переменная создается. С его помощью возвращаемое значение сохраняется где-то еще, возможно, более эффективным способом.

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Как прокомментировано, основные накладные расходы - это использование % вместо условия или маски

Вы можете запустить тест с JMH

static class Foo {

}

Foo[] array = new Foo[8];
int index = 0;

@Benchmark
public Foo simple() {
    Foo result = array[index];
    index = (index + 1) % array.length;
    return result;
}

@Benchmark
public Foo withFinally() {
    try {
        return array[index];
    } finally {
        index = (index + 1) % array.length;
    }
}

@Benchmark
public Foo withCondition() {
    int i = index++;
    if (index == array.length) index = 0;
    return array[i];
}

@Benchmark
public Foo withMask() {
    int i = index++;
    return array[i & (array.length-1)];
}

Результаты на моей машине ... Ваш пробег Будет Варьируется

Benchmark               Mode  Cnt    Score   Error   Units
ModMain.simple         thrpt   25  132.473 ± 1.764  ops/us
ModMain.withCondition  thrpt   25  363.077 ± 4.752  ops/us
ModMain.withFinally    thrpt   25  130.179 ± 1.585  ops/us
ModMain.withMask       thrpt   25  397.310 ± 3.506  ops/us

Чем выше, тем лучше.

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

0 голосов
/ 02 июля 2018

Без finally вы действительно объявляете дополнительную переменную Foo.
Но действительно ли это дорого? Не так, как в обоих случаях, объект Foo существует в памяти. Вы только что добавили ссылку для доступа к ней.
Ссылка на объект в области действия метода очень дешева.
Вы никогда не должны беспокоиться об этом.

Кроме того, вам не нужно использовать оператор finally как способ улучшить производительность исполняемого кода.
Читатели кода никогда не догадаются об этом.
finally служит для:

Блок finally всегда выполняется при выходе из блока try. это гарантирует, что блок finally выполняется, даже если неожиданный возникает исключение.

и

размещение кода очистки в блоке finally - это всегда хорошая практика, даже когда не ожидается никаких исключений.

Первый код без оператора finally намного понятнее и не имеет никакого косвенного чтения.

Так что советую придерживаться:

Foo result = array[index];
index = (index + 1) % array.length;
return result;  
...