Должен попробовать выгоду …, входят или вне цикла?

В Java все находится в форме класса.

Если вы хотите использовать любой объект, тогда у вас есть две фазы:

  1. Объявить
  2. Инициализация

Пример:

  • Объявление: Object a;
  • Инициализация: a=new Object();

То же самое для концепции массива

  • Объявление: Item i[]=new Item[5];
  • Инициализация: i[0]=new Item();

Если вы не дают секцию инициализации, тогда возникает NullpointerException.

175
задан Michael Myers 21 December 2012 в 00:29
поделиться

17 ответов

Хорошо, после Jeffrey L Whitledge сказал , что не было никакого различия в производительности (по состоянию на 1997), я пошел и протестировал его. Я выполнил этот маленький сравнительный тест:

public class Main {

    private static final int NUM_TESTS = 100;
    private static int ITERATIONS = 1000000;
    // time counters
    private static long inTime = 0L;
    private static long aroundTime = 0L;

    public static void main(String[] args) {
        for (int i = 0; i < NUM_TESTS; i++) {
            test();
            ITERATIONS += 1; // so the tests don't always return the same number
        }
        System.out.println("Inside loop: " + (inTime/1000000.0) + " ms.");
        System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms.");
    }
    public static void test() {
        aroundTime += testAround();
        inTime += testIn();
    }
    public static long testIn() {
        long start = System.nanoTime();
        Integer i = tryInLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static long testAround() {
        long start = System.nanoTime();
        Integer i = tryAroundLoop();
        long ret = System.nanoTime() - start;
        System.out.println(i); // don't optimize it away
        return ret;
    }
    public static Integer tryInLoop() {
        int count = 0;
        for (int i = 0; i < ITERATIONS; i++) {
            try {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            } catch (NumberFormatException ex) {
                return null;
            }
        }
        return count;
    }
    public static Integer tryAroundLoop() {
        int count = 0;
        try {
            for (int i = 0; i < ITERATIONS; i++) {
                count = Integer.parseInt(Integer.toString(count)) + 1;
            }
            return count;
        } catch (NumberFormatException ex) {
            return null;
        }
    }
}

я проверил получающийся байт-код с помощью javap, чтобы удостовериться, что ничто не было встроено.

результаты показали, что, принимая незначительную оптимизацию JIT, Jeffrey корректен ; существует абсолютно никакое различие в производительности на Java 6, клиент VM Sun (у меня не было доступа к другим версиям). Различие общего времени находится на порядке нескольких миллисекунд по всему тесту.

Поэтому единственное соображение что самые чистые взгляды. Я нахожу, что второй путь ужасен, таким образом, я буду придерживаться или первого пути или путь Ray Hayes .

46
ответ дан Community 23 November 2019 в 20:27
поделиться

ПРОИЗВОДИТЕЛЬНОСТЬ:

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

Вот ссылка: http://www.javaworld.com/javaworld/jw-01-1997/jw-01-hood.html

таблица описана о промежуточном вниз.

122
ответ дан Jeffrey L Whitledge 23 November 2019 в 20:27
поделиться

Я помещу свой дюйм за 0,02$. Иногда Вы волнуете необходимость добавить "наконец" позже в Вашем коде (потому что, кто когда-нибудь пишет их коду отлично первый раз?). В тех случаях внезапно имеет больше смысла иметь попытку/выгоду вне цикла. Например:

try {
    for(int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        dbConnection.update("MY_FLOATS","INDEX",i,"VALUE",myNum);
    }
} catch (NumberFormatException ex) {
    return null;
} finally {
    dbConnection.release();  // Always release DB connection, even if transaction fails.
}

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

1
ответ дан Ogre Psalm33 23 November 2019 в 20:27
поделиться

Это зависит от обработки отказа. Если Вы просто хотите пропустить ошибочные элементы, попробуйте внутри:

for(int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    } catch (NumberFormatException ex) {
        --i;
    }
}

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

1
ответ дан Arne Burmeister 23 November 2019 в 20:27
поделиться

Я похож для добавления моего собственного 0.02c приблизительно два конкурирующих соображения при рассмотрении общей проблемы того, где расположить обработку исключений:

  1. "шире" ответственность try-catch блок (т.е. вне цикла в Вашем случае) означает, что при изменении кода в некоторой более поздней точке, можно по ошибке добавить строку, которая обрабатывается существующим catch блок; возможно неумышленно. В Вашем случае это менее вероятно, потому что Вы явно ловите NumberFormatException

  2. , Чем "более узкий" ответственность try-catch блок, тем более трудный рефакторинг становится. Особенно, когда (как в Вашем случае) Вы выполняете "нелокальную" инструкцию из catch блок (return null оператор).

1
ответ дан oxbow_lakes 23 November 2019 в 20:27
поделиться

Смысл исключений должен поощрить первый стиль: разрешение обработке ошибок быть консолидированным и обработанным однажды, не сразу на каждом возможном ошибочном сайте.

1
ответ дан wnoise 23 November 2019 в 20:27
поделиться

Если это будет внутри, то Вы получите издержки структуры попытки/выгоды N времена, в противоположность просто однажды на внешней стороне.

<час>

Каждый раз, когда структуру Попытки/Выгоды называют, она добавляет наверху к осуществлению метода. Просто немного памяти & галочки процессора должны были иметь дело со структурой. При выполнении цикла 100 раз, и для гипотетической пользы скажем, стоимость является 1 галочкой на вызов попытки/выгоды, то наличие Попытки/Выгоды в цикле стоит Вам 100 галочек, в противоположность только 1 галочке, если это за пределами цикла.

1
ответ дан Stephen Wrighton 23 November 2019 в 20:27
поделиться

установка специального стекового фрейма для попытки/выгоды добавляет дополнительные издержки, но JVM может быть в состоянии обнаружить то, что Вы возвращаете и оптимизируете это далеко.

в зависимости от количества повторений, различие в производительности, вероятно, будет незначительно.

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

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

1
ответ дан Matt 23 November 2019 в 20:27
поделиться

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

На другой ноте необходимо, вероятно, посмотреть на плавание. TryParse или Преобразовывают. ToFloat.

2
ответ дан Orion Adrian 23 November 2019 в 20:27
поделиться

В Ваших примерах нет никакого функционального различия. Я нахожу Ваш первый пример более читаемым.

2
ответ дан Jamie 23 November 2019 в 20:27
поделиться

Если бескомпромиссный сбой, то первый формат имеет смысл. Если Вы хотите быть в состоянии обработать/возвратить все непровальные элементы, необходимо использовать вторую форму. Те были бы моими основными критериями выбора между методами. Лично, если бы это является бескомпромиссным, я не использовал бы вторую форму.

4
ответ дан Joe Skora 23 November 2019 в 20:27
поделиться

вставьте его. Можно продолжать обрабатывать (если Вы хотите), или можно выдать полезное исключение, которое говорит клиенту значение myString и индекс массива, содержащего плохое значение. Я думаю, что NumberFormatException уже скажет Вам плохое значение, но принцип должен поместить все полезные данные в исключения, которые Вы выдаете. Думайте о том, что было бы интересно Вам в отладчике в этой точке в программе.

Рассмотрите:

try {
   // parse
} catch (NumberFormatException nfe){
   throw new RuntimeException("Could not parse as a Float: [" + myString + 
                              "] found at index: " + i, nfe);
} 

Во время потребности Вы будете действительно ценить исключение как это с как можно большей информацией в нем.

1
ответ дан Kyle Dyer 23 November 2019 в 20:27
поделиться

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

5
ответ дан user19810 23 November 2019 в 20:27
поделиться

Я соглашаюсь со всей производительностью и сообщениями удобочитаемости. Однако существуют случаи, где это действительно имеет значение. Пара других людей упомянула это, но могло бы быть легче видеть с примерами.

Рассматривают этот немного измененный пример:

public static void main(String[] args) {
    String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
    ArrayList asNumbers = parseAll(myNumberStrings);
}

public static ArrayList parseAll(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        myFloats.add(new Float(numberStrings[i]));
    }
    return myFloats;
}

, Если Вы хотите, чтобы parseAll () метод возвратил пустой указатель, если существуют какие-либо ошибки (как исходный пример), Вы поместили пробование/завоевывание популярность внешней стороны как это:

public static ArrayList parseAll1(String[] numberStrings){
    ArrayList myFloats = new ArrayList();
    try{
        for(int i = 0; i < numberStrings.length; i++){
            myFloats.add(new Float(numberStrings[i]));
        }
    } catch (NumberFormatException nfe){
        //fail on any error
        return null;
    }
    return myFloats;
}

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

, С другой стороны, если Вы хотите, чтобы он просто проигнорировал проблемы и проанализировал безотносительно Строк, это может, Вы поместили пробование/завоевывание популярность внутренней части цикла как это:

public static ArrayList parseAll2(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        try{
            myFloats.add(new Float(numberStrings[i]));
        } catch (NumberFormatException nfe){
            //don't add just this one
        }
    }

    return myFloats;
}
13
ответ дан Matt N 23 November 2019 в 20:27
поделиться

Производительность : как Jeffrey, сказанный в его ответе, в Java, это не имеет большого значения.

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

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

третий путь : Вы могли всегда писать свой собственный статический метод ParseFloat и иметь обработку исключений, с которой имеют дело с в том методе, а не Вашем цикле. Создание обработки исключений, изолированной к самому циклу!

class Parsing
{
    public static Float MyParseFloat(string inputValue)
    {
        try
        {
            return Float.parseFloat(inputValue);
        }
        catch ( NumberFormatException e )
        {
            return null;
        }
    }

    // ....  your code
    for(int i = 0; i < max; i++) 
    {
        String myString = ...;
        Float myNum = Parsing.MyParseFloat(myString);
        if ( myNum == null ) return;
        myFloats[i] = (float) myNum;
    }
}
70
ответ дан Community 23 November 2019 в 20:27
поделиться

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

2
ответ дан Joel Coehoorn 23 November 2019 в 20:27
поделиться

Еще одним аспектом, не упомянутым выше, является тот факт, что каждая попытка оказывает некоторое влияние на стек, что может иметь последствия для рекурсивных методов.

Если метод "outer()" вызывает метод "inner()" (который может вызывать себя рекурсивно), попробуйте найти try-catch в методе "outer()", если это возможно. Простой пример «сбоя стека», который мы используем в классе производительности, терпит неудачу примерно на 6 400 кадрах, когда try-catch находится во внутреннем методе, и примерно на 11 600, когда он находится во внешнем методе.

В реальном мире это может быть проблемой, если вы используете шаблон Composite и имеете большие, сложные вложенные структуры.

1
ответ дан 23 November 2019 в 20:27
поделиться
Другие вопросы по тегам:

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