Производительность и дизайн, связанные с частными/защищенными методами в java

Мы обсуждаем с другом дизайн и эффективность кода Java.

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

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

Мы знаем, что композиция предпочтительнее наследования так что здесь я в основном фокусируюсь на сравнении производительности.

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

elapsed:8051733.063 microseconds for A (private)
elapsed:8036953.805 microseconds for B (protected)

Считаете ли вы, что приведенный ниже тест достаточно надежен для проведения сравнения?

public class VerifPerfProtected {
public static void main(String[] args) {
    int ncalls = 1000000000; //10^9
    ChildrenClassA a = new ChildrenClassA();
    ChildrenClassB b = new ChildrenClassB();

    long start = System.nanoTime();
    a.manyCalls(ncalls);
    long stop = System.nanoTime();
    System.out.println("elapsed:" + (stop - start)/1000.0 + " microseconds for A (private)");

    start = System.nanoTime();
    b.manyCalls(ncalls);
    stop = System.nanoTime();
    System.out.println("elapsed:" + (stop - start)/1000.0 + " microseconds for B (protected)");
}

public static class ParentClassA{
    public void manyCalls(int n){
        for (int i = 0; i < n; i++) {
            callAmethod();
        }
    }
    public void callAmethod(){
        aPrivateMethod();
    }
    private void aPrivateMethod(){
        int a=0;
        for (int i = 0; i < 5; i++) {
            a++;
        }
    }
}

public static class ParentClassB{
    public void manyCalls(int n){
        for (int i = 0; i < n; i++) {
            callAmethod();
        }
    }
    public void callAmethod(){
        aProtectedMethod();
    }
    protected void aProtectedMethod(){
        int a=0;
        for (int i = 0; i < 5; i++) {
            a++;
        }
    }
}

public static class ChildrenClassA extends ParentClassA{        
}

public static class ChildrenClassB extends ParentClassB{        
}
}

person Martin    schedule 08.02.2012    source источник
comment
Вы звоните оба раза. Опечатка или баг?   -  person PaulJWilliams    schedule 08.02.2012
comment
Моя ошибка... Я обновил код и результаты производительности. Спасибо.   -  person Martin    schedule 08.02.2012


Ответы (4)


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

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

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

person Peter Lawrey    schedule 08.02.2012

Считаете ли вы, что приведенный ниже тест достаточно надежен для проведения сравнения?

Честно говоря, нет.

Микротесты сложны; здесь хорошее обсуждение их. Лично я всегда добавляю время прогрева (например, первые x раз, когда я запускаю метод, не учитываются для производительности, давая различным синглтонам возможность инициализироваться и давая JIT-компилятору время сделать свое волшебство), и я обязательно запускаю JVM с переключателем -server. Кроме того, я подозреваю, что компилятор может быть достаточно умен, чтобы удалить операции a++, поскольку их результат никуда не денется.

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

person Eli Acherkan    schedule 08.02.2012
comment
Конечно, если вы тестируете время запуска клиентской JVM, вам не нужен прогрев или -server. - person Tom Hawtin - tackline; 08.02.2012

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

Но ваш бенчмарк некорректен. С обратной стороны конверта 1 000 000 000 звонков за 8 000 000 микросекунд. Это 8 нс для вашего метода с циклом. HotSpot разумно способен встраивать вызовы виртуальных методов. Ваш код будет лучше с разминкой, повторите несколько раз и посмотрите на вариацию, а также на среднее значение. Кроме того, если вы чередуете алгоритмы, HotSpot, возможно, придется пессимизировать при обмене.

Что еще более важно, защита — это зло.

person Tom Hawtin - tackline    schedule 08.02.2012

Я бы предпочел частные методы по двум причинам:

  • инкапсуляция: держите вещи как можно более приватными. Защищайте методы только в том случае, если они действительно предназначены для переопределения. Упрощает рефакторинг и модульное тестирование, поскольку вы можете переименовывать/перемещать/разделять/и т. д. частные методы без риска каких-либо побочных эффектов где-либо еще в вашей кодовой базе.
  • оптимизация: компилятору JIT легче оптимизировать частные методы (встроенные и т. д.), потому что он знает, что они нигде не переопределяются.
person Olivier Croisier    schedule 08.02.2012
comment
Я не верю, что клиент или сервер HotSpot особенно заботятся о том, является ли метод закрытым, чтобы определить, переопределен ли он. Клиент записывает, переопределяет ли какой-либо загруженный класс. Сервер умнее этого. - person Tom Hawtin - tackline; 08.02.2012
comment
Я хочу сказать, что вы можете думать, что метод никогда не будет переопределен, и один из ваших пользователей может захотеть это сделать... - person Martin; 08.02.2012
comment
optimization? у вас есть источник / ссылка? - person Yousha Aleayoub; 19.09.2016