2011-01-29 3 views
1

Когда я смотрел на свой код, появилось много вопросов. Я хотел бы знать, что люди думают о некоторых фрагментах кода. Для каждого из них мне интересно, что более оптимизировано, и что лучше или чище. Скорее всего, любая возможная оптимизация зависит от масштаба наносекунд, мне просто интересно теоретически. :)Вопросы оптимизации Java

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

if(success) 
//Stuff 
else 
reportInternalError(); 

Есть ли польза для изменения его

if(success) { 
//Stuff 
return; 
} 
reportInternalError(); 

2) reportInternalError() должен только сообщить об ошибке в первый раз это происходит, и это потенциально может быть очень часто. В настоящее время это, как этот

if(!reported) { 
//Report error 
reported = true; 
} 

Я имею в виду, об изменении его

if(reported) 
return; 
//Report error 
reported = true; 

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

try { 
//Stuff 
} catch(){ 
} 

while(loop) { 
try { 
    //Same Stuff 
} catch(){ 
    loop = false; 
} 
} 

Versus

first = true; 
do { 
try { 
    //Stuff 
} catch() { 
    if(!first) 
     loop = false; 
} 
first = false; 
} while(loop); 

Спасибо!

+1

Правильно, разница в производительности во время выполнения будет невероятно negible никто никогда не заметит. Вы даже не должны думать об этом, даже теоретически, поскольку это полная трата времени;) – delnan

ответ

2

я бы поставил премию по читаемости и ремонтопригодность над микро-оптимизации. Прибыль от микро-оптимизации действительно небрежна (и часто из-за сложности современных компиляторов, JIT и процессоров).

Мой выбор:

1) Я пытаюсь поставить нормальный случай вдоль основного пути кода и исключительных ситуаций в филиалах:

if (! success) { 
    reportInternalError(); 
} 

// Stuff 

2) Я предпочитаю оригинальный подход. Другой способ предполагает, что метод всегда будет просто хотеть return, но что, если ему нужно делать больше вещей в будущем? Я не хочу, что дополнительный материал, чтобы идти в отрасли:

if (! reported) { 
    // Report error 
    reported = true; 
} 
// extra stuff to do 

3) переработана версия кажется более ремонтопригодна мне. Я на заборе о замене targetExceptionWasThrown с простой break:

boolean isFirstIteraton = true; 
boolean targetExceptionWasThrown = false; 
do { 
    try { 
     //Stuff 
    } catch() { 
     if (! isFirstIteraton) { 
      targetExceptionWasThrown = true; 
     } 
    } 
    isFirstIteraton = false; 
} while (! targetExceptionWasThrown); 
+0

Спасибо, ты дал много оснований для своих выборов. –

+1

@Kevin S - спасибо. Я думаю, что логическое обоснование важно, потому что: (1) я мог ошибиться в логике и хочу, чтобы кто-то меня исправил. (2) Нет абсолютного правильного способа делать то, что охватывает все случаи - вам нужно знать, что нужно знать, когда нужно отклоняться. –

4

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

Кроме того, JIT-компилятор JVM, скорее всего, сделает эти оптимизации для вас. И даже если это не так, стало настолько сложно, что изменения, которые выглядят как увеличение производительности, могут фактически замедлить работу программы. Джош Блох дал отличную presentation на эту тему в Devoxx в прошлом году.

+3

Один из моих преподавателей по программированию имел хорошее высказывание по этому поводу: «Не пытайтесь перехитрить компилятор» – esaj

2

Что касается №3, исключение «выйдет» из цикла для вас, просто положите try-catch вне цикла.

try { 
//Stuff 
} catch(){ 
} 

try { 
    while(true) { 
    //Same Stuff 
    } 
} catch(){ 
} 

Но поскольку у вас есть некоторое количество дублирования, использующее break во втором примере может быть лучше (вместо loop вара).

first = true; 
while (true) { 
try { 
    //Stuff 
} catch() { 
    if(!first) 
     break; 
} 
first = false; 
}; 

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

1

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

+0

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

1

Как теоретически, так и практически ваш компилятор должен обрабатывать такую ​​микро-оптимизацию, а не вы. Сосредоточьтесь на ясности и придерживайтесь идиомы с одним возвратом: каждая функция/метод должна иметь один оператор return, в конце.

В третьем примере ваше намерение состоит в том, чтобы выполнить блок try/catch не менее двух раз. Попробуйте

for (int i=0; i<2 || loop; i++) { 
    // put the try/catch block here 
} 
1

Я согласен с другими ответами, что вы не должны пытаться перехитрить компилятор для производительности и вместо этого сосредоточиться на читаемости. Что я использую, когда я имею дело 1 и 2 заключается в следующем:

случай 1:

if(! success) { 
    reportInternalError(); 
    return; 
} 

// do Stuff 

и для случая 2:

if(reported) 
return; 

//Report error 
reported = true; 

В основном это шаблон пункт охраны. http://www.c2.com/cgi/wiki?GuardClause. Это работает правильно, когда вы хотите убедиться, что некоторый инвариант встречен перед запуском вашего кода. Я думаю, что в этом случае можно нарушить правило множественных возвратов. И это упрощает чтение кода, потому что я могу сразу проверить, какие условия должны быть выполнены перед запуском кода.

Что касается # 3 я бы написать так:

try { 

     boolean finished = false; 
     do { 

      //Same Stuff 

      if (/* end of loop test */) { 
       finished = true; 
      } 
     } while (! finished); 
    } catch() { 
     // handle exception  
    }