2013-08-04 5 views
8

Рассмотрим такой метод:Должен ли я кэшировать System.getProperty ("line.separator")?

@Override 
public String toString() 
{ 
    final StringBuilder sb = new StringBuilder(); 
    for (final Room room : map) 
    { 
     sb.append(room.toString()); 
     sb.append(System.getProperty("line.separator")); // THIS IS IMPORTANT 
    } 
    return sb.toString(); 
} 

System.getProperty("line.separator") можно назвать много раз.

Следует ли кэшировать это значение с помощью public final static String lineSeperator = System.getProperty("line.separator") , а затем использовать только lineSeperator?

Или System.getProperty("line.separator") так же быстро, как использование статического поля?

+0

Я думаю, что System.getProperty должен искать указанный ключ каждый раз, когда вы его вызываете. Я не знаю, делает ли компилятор оптимизацию. Давайте посмотрим, что предлагают люди. – Fedy2

+0

Используете ли вы Java 7 или более старую версию? – chrylis

+0

@chrylis Я использую 6, я думаю начать с 7 (до сих пор я не вижу серьезных причин для обновления ...). Есть ли разница между 6 и 7 с этим 'getProperty()'? –

ответ

3

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

@Override 
public String toString() 
{ 
    final StringBuilder sb = new StringBuilder(); 
    final String newline = System.getProperty("line.separator"); 
    for (final Room room : map) sb.append(room.toString()).append(newline); 
    return sb.toString(); 
} 

BTW Я проверил вызов.Код:

public class GetProperty 
{ 
    static char[] ary = new char[1]; 
    @GenerateMicroBenchmark public void everyTime() { 
    for (int i = 0; i < 100_000; i++) ary[0] = System.getProperty("line.separator").charAt(0); 
    } 
    @GenerateMicroBenchmark public void cache() { 
    final char c = System.getProperty("line.separator").charAt(0); 
    for (int i = 0; i < 100_000; i++) ary[0] = (char)(c | ary[0]); 
    } 
} 

Результаты:

Benchmark      Mode Thr Cnt Sec   Mean Mean error Units 
GetProperty.cache   thrpt 1  3 5  10.318  0.223 ops/msec 
GetProperty.everyTime  thrpt 1  3 5  0.055  0.000 ops/msec 

кэшируются подход более чем на два порядка быстрее.

Обратите внимание, что общее воздействие getProperty вызывает все строковое строение, очень маловероятно, чтобы быть заметным.

+0

не очень хороший ответ, если кеширование происходит быстрее, вы должны кэшировать его до статического, что, если вы несколько раз вызываете 'toString'? – Enerccio

+0

Системное свойство может меняться между вызовами. В частности, пользователь может установить его только один раз, но после того, как этот класс уже был инициализирован. С другой стороны, статическое кэширование будет выигрывать один доступ на вызов 'toString', только если количество элементов на карте очень мало. Вы не можете утверждать, что это «не очень хороший ответ», упомянув альтернативу, которая просто имеет разные компромиссы, чем эта. –

3

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

Кэширование значения, безусловно, быстрее, чем выполнение вызова снова и снова, но разница, вероятно, будет незначительной.

+1

Зависит от того, включен ли вызов во время оптимизации хот-спота :) –

+1

О, хорошо, хорошо. Но мне лично не нравится полагаться на такие функции - не лучше ли иметь код, который * уже * выглядит эффективным? – MightyPork

+0

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

1

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

Если вы этого не сделали, то нет, поиск вряд ли будет иметь достаточное количество накладных расходов.

Это подпадает под любую или обе из общих категорий «микро-оптимизация» и «преждевременная оптимизация». :-)


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

@Override 
public String toString() 
{ 
    if (cachedString == null) 
    { 
     final StringBuilder sb = new StringBuilder(); 
     final String ls = System.getProperty("line.separator"); 
     for (final Room room : map) 
     { 
      sb.append(room.toString()); 
      sb.append(ls); 
     } 
     cachedString = sb.toString(); 
    } 
    return cachedString; 
} 

... и когда ваши изменения карты, сделать

cachedString = null; 

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

+1

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

+2

@assylias: Во-первых, позвольте мне сказать: мало кто хуже, чем преждевременная оптимизация чем я. :-) Но ПО не является (только) о создании плохого кода. Речь идет о том, чтобы тратить время, энергию и память на оптимизацию вещей, которые не нуждаются в оптимизации, когда вы * могли бы использовать это время, энергию и память, оптимизируя вещи, которые * нуждаются в оптимизации или добавлении к функциональности. –

+0

@ T.J.Crowder Мне нечего противопоставить этому, но в этом конкретном случае я бы извлек локальную переменную с тем, что производительность даже не приходила мне в голову. –

2

Поскольку так легко сделать, почему бы и нет? По крайней мере, реализация System.getProperty() должна будет искать хэш-таблицу (даже если она кэширована изнутри), чтобы найти запрашиваемое свойство, тогда виртуальный метод getString() будет вызываться в результирующем объекте. Ни один из них не очень дорогой, но его нужно будет называть несколько раз. Не говоря уже о том, что будут созданы временные файлы String и после этого им потребуется GCing.

Если вы переместите это в верхнюю часть цикла и повторно используете одно и то же значение, вы избежите всех этих проблем. Так почему бы не?

+4

* «Так как это так легко сделать, почему бы и нет?» * Потому что, если это не имеет значения, создание дополнительных статических полей - плохая идея. Должен ли каждый класс, который использует любое системное свойство, которое не изменяется, сохраняет свою собственную копию? И другие вещи, которые не меняются? Когда нет четкого повышения производительности? Нет. Это просто приводит к загромождению памяти избыточной информацией. –

+2

Я согласен, и я действительно хотел вычислить его один раз внутри функции, прежде чем входить в цикл. Я не заметил, что OP использовал предложение с использованием статического значения. –

+0

@ alex: Ах, да, это другое.:-) –

0

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

Например, текстовый генератор может использовать свойство для генерации текста для окон или для linux и разрешить динамическое изменение свойства в приложении, почему бы и нет?

В общем, улавливание имущества подразумевает использование бесполезной функции setProperty.

Смежные вопросы