Имейте в виду, что независимо от сценария причина всегда одинакова в .NET:
Вы пытаетесь использовать ссылочную переменную, значение которой
Nothing
/null
. Если для ссылочной переменной значениеNothing
/null
, это означает, что на самом деле оно не содержит ссылку на экземпляр любого объекта, который существует в куче.Вы либо никогда не присваивали какую-либо переменную, никогда не создавали экземпляр значения, присвоенного переменной, или вы вручную устанавливали переменную, равную
blockquote>Nothing
/null
, или вы вызывали функцию, которая установите для этой переменной значениеNothing
/null
.
Было бы более оптимальным для меня просто копировать и вставлять две строки в свой метод clear () в конструктор вместо вызова фактического метода?
blockquote>Компилятор может выполнить эту оптимизацию. И так может JVM. Терминология, используемая авторами-компиляторами и авторами JVM, является «встроенным расширением».
Если да, то какая разница делает это?
blockquote>Измерьте это. Часто вы обнаружите, что это не имеет значения. И если вы считаете, что это горячая точка производительности, вы смотрите не в то место; поэтому вам нужно его измерить.
Что делать, если мой конструктор выполнил 10 вызовов метода, каждый из которых просто установил переменную экземпляра в значение?
blockquote>Опять же, это зависит от сгенерированного байт-кода и любых оптимизаций во время выполнения, выполняемых виртуальной машиной Java. Если компилятор / JVM может встроить вызовы метода, он будет выполнять оптимизацию, чтобы избежать накладных расходов на создание новых кадров стека во время выполнения.
Какая лучшая практика программирования?
blockquote>Избегайте преждевременной оптимизации. Лучшей практикой является запись читаемого и хорошо продуманного кода, а затем оптимизация для горячих точек производительности в вашем приложении.
Учитывая память современных компьютеров, это очень недорого. Всегда лучше разбить код на методы, чтобы кто-то мог быстро прочитать, что происходит. Это также поможет с сокращением ошибок в коде, если ошибка ограничивается одним методом с телом нескольких строк.
Стоимость вызова метода - это создание (и удаление) фрейма стека и некоторых дополнительных выражений в байтовом коде, если вам нужно передать значения методу.
Лучшая практика состоит в том, чтобы дважды измерять и вырезать один раз.
Как только вы потратили время на оптимизацию времени, вы никогда не сможете вернуть его снова! (Так что сначала измерьте это и спросите себя, стоит ли оптимизировать. Сколько фактического времени вы сохраните?)
В этом случае Java VM, вероятно, уже делает оптимизацию, о которой вы говорите.
Я бы не стал беспокоиться о вызове метода, но о логике метода. Если это были критические системы, и система должна была быть «быстрой», я бы посмотрел на оптимизирующие коды, которые занимают много времени.
То, что все остальные говорили об оптимизации, абсолютно верно.
Нет причин с точки зрения производительности , чтобы встроить метод. Если это проблема с производительностью, JIT в вашей JVM включит ее. В java вызовы методов настолько близки к свободным, что не стоит об этом думать.
Говоря, здесь есть другая проблема. А именно, является плохой практикой программирования для вызова переопределяемого метода (т. Е. Того, который не является final
, static
или private
) из конструктора. (Эффективная Java, 2-е изд., Стр. 89 в элементе под названием «Дизайн и документ для наследования или запрет»)
Что произойдет, если кто-то добавит подкласс BinarySearchTree
, названный LoggingBinarySearchTree
, который переопределяет все общедоступные методы с помощью кода типа:
public void clear(){
this.callLog.addCall("clear");
super.clear();
}
Тогда LoggingBinarySearchTree
никогда не будет конструктивным! Проблема в том, что this.callLog
будет null
, когда работает конструктор BinarySearchTree
, но clear
, который вызывается, является переопределенным, и вы получите NullPointerException
.
Обратите внимание, что Java и C ++ отличаются здесь: в C ++ конструктор суперкласса, который вызывает метод virtual
, заканчивает вызов того, что определено в суперклассе, а не переопределенном. Люди, переключающиеся между двумя языками, иногда забывают об этом.
Учитывая, что, по-моему, в вашем случае, возможно, более чистым является включение метода clear
при вызове из конструктора , но в общий на Java, вы должны идти вперед и делать все вызовы методов, которые вы хотите.
Сохраняйте метод clear()
, когда он помогает читать. Недопустимый код более дорогой.
Я бы определенно оставил это как есть. Что, если вы измените логику clear()
? Было бы нецелесообразно находить все места, где вы скопировали 2 строки кода.
Как говорили другие, стоимость вызова метода тривиальна к-наде, поскольку компилятор оптимизирует его для вас.
Тем не менее, существует опасность в вызове методов вызова методам экземпляра из конструктора. Вы рискуете позже обновить метод экземпляра, чтобы попытаться использовать переменную экземпляра, которая еще не была инициирована конструктором. То есть вы не обязательно хотите отделять конструкторскую работу от конструктора.
Другой вопрос: ваш метод clear () устанавливает корень в EMPTY, который инициализируется при создании объекта. Если вы затем добавите узлы в EMPTY, а затем вызовите clear (), вы не сбросите корневой узел. Это поведение, которое вы хотите?
Вообще говоря (и как новичок это всегда означает!), вы никогда не должны делать микрооптимизации, как тот, который вы рассматриваете. Всегда предпочитайте читаемость кода над такими вещами.
Почему? Потому что компилятор / точка доступа сделает эти виды оптимизаций для вас «на лету» и многие, многие другие. Во всяком случае, когда вы пытаетесь сделать оптимизацию по этим типам строк (хотя и не в этом случае), вы, вероятно, будете делать что-то медленнее. Точка зрения понимает общие идиомы программирования, если вы попытаетесь сделать эту оптимизацию самостоятельно, она, вероятно, не поймет, что вы пытаетесь сделать, поэтому она не сможет ее оптимизировать.
Там также намного больше стоимость технического обслуживания. Если вы начнете повторять код, это будет гораздо больше усилий для поддержания, что, вероятно, будет намного сложнее, чем вы могли бы подумать!
. В стороне, вы можете получить некоторые моменты в своей жизни кодирования где вам нужно сделать оптимизацию на низком уровне, но если вы нажмете эти очки, вы определенно узнаете, когда придет время. И если вы этого не сделаете, вы можете всегда вернуться и оптимизировать позже, если вам нужно.
Оптимизация компиляторов обычно делает довольно хорошую работу по удалению избыточности из этих «дополнительных» операций; во многих случаях разница между «оптимизированным» кодом и кодом просто написана так, как вы хотите, и работать с оптимизирующим компилятором - нет; то есть оптимизирующий компилятор обычно выполняет такую же хорошую работу, как и вы, и делает это, не вызывая ухудшения исходного кода. На самом деле, много раз, «оптимизированный вручную» код заканчивается ЛЕГКО эффективным, потому что компилятор учитывает многие вещи при выполнении оптимизации. Оставьте свой код в читаемом формате и не беспокойтесь об оптимизации до более позднего времени.
«Преждевременная оптимизация - это корень всего зла». - Дональд Кнут
blockquote>
Образец, который я следую, заключается в том, удовлетворяет ли этот метод одному из следующих:
Если любое из приведенных выше значений истинно, оно должно быть завершено в собственном методе.