Comments 91
oneByte размером с int это круто!
-5
java.io.InputStream
public abstract int read() throws IOException
Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
java.lang.Byte
MAX_VALUE A constant holding the maximum value a byte can have, 2^7-1
MIN_VALUE A constant holding the minimum value a byte can have, -2^7.
+2
Я знаю, в C getchar() тоже int возвращает дабы была возможность детектировать ошибку.
Но всё равно выглядит очень странно такое название переменной и тип int.
Но всё равно выглядит очень странно такое название переменной и тип int.
-1
int odin = 2;
— как один тут товарищ писал, это странно, да :) +6
В С — как раз ничего странного. Где это возможно, используется тип int, т.к. он привязан к архитектуре процессора, под которую собран код — и обычно это максимально быстрая единица памяти, к которой имеет доступ процессор. Другими словами, экономия при объявлении переменной может обернуться либо тем же расходом памяти (в случае если компилятор их выровняет по границам, кратным размеру int), либо медленным доступом.
+1
крошка сын к отцу пришел, и спросила кроха… :)
+4
> В случае явного указания значений для полей класса — они будут проинициализированы до вызова конструктора, что влечет дополнительные расходы.
Какие расходы? На что?
Какие расходы? На что?
+1
UFO just landed and posted this here
Интересный вариант, но стаття как раз про то как не нужно делать. Поэтому preconditions в конструкторе не очень хороший вариант =).
+2
UFO just landed and posted this here
Если исходить из Ваших условий — приватный конструктор и статический метод в классе, который осуществит нужные проверки и вернет корректный обьект или ошибку.
+1
Шаблон «фабрика» спешит на помощь.
0
Я знал, что обязательно кто-то это подметит. Шаблоны тем не менее не всегда уместны. На хабре была стаття по этому поводу.
0
Шаблоны уместны там, где они… уместны.
И проверка всяких условий перед фактическим созданием объекта — как раз одно из мест, где применение шаблона «фабрика» просто напрашивается.
И проверка всяких условий перед фактическим созданием объекта — как раз одно из мест, где применение шаблона «фабрика» просто напрашивается.
+2
Тоесть для этого примера я должен был бы создать шаблон «фабрика»?
0
Боюсь вам разочаровать, но шаблон «абстрактная фабрика» был создан и описан умными бородатыми дядьками в умной тонкой книжке почти двадцать лет назад…
+2
Что характерно, doom369 собственно фабрику и предлагает использовать: habrahabr.ru/blogs/java/132374/#comment_4396258
0
Вы трижды одинаково опечатались в слове «статья». Это настораживает
+1
UFO just landed and posted this here
В случае если вы создаете обьект с пустым конструктором и инициализация полей Вам не нужна. А в пределах приложения это может быть существенно. В любом случае Вы правы, этот момент нужно подправить.
0
Например на
private List zzz = new ArrayList();
private List zzz = new ArrayList();
0
А разница с тем, что он создастся в констукторе?
0
Например в конструкторе может быть дополнительная логика, которая будет менять/отменять инициализацию либо выполнять инициализацию полей более эффективным способом.
Пример: конструктор принимает список элементов, эффективней будет сделать zzz = new ArrayList(providedValues), чем вначале просто проинициализировать список, а потом добавить в него элементы.
Пример: конструктор принимает список элементов, эффективней будет сделать zzz = new ArrayList(providedValues), чем вначале просто проинициализировать список, а потом добавить в него элементы.
0
UFO just landed and posted this here
Быть может повторюсь, но тем не менее.
Есть еще полезный прием:
Позволяет избежать NPE при сравнении строк с константами.
Есть еще полезный прием:
"true".equals(str)
Позволяет избежать NPE при сравнении строк с константами.
+9
В принципе — да… Тем не менее 90% случаев сравнения строк — это
Этот случай больно уж редкий.
label.equals(str)
Этот случай больно уж редкий.
-7
Не очень удачный пример, конкретно в данном случае лучше Boolean.valueOf(str);
Но для других, нестандартных строк, действительно хороший вариант.
Но для других, нестандартных строк, действительно хороший вариант.
-2
Так же очень удобно использовать null-safe
или
Objects.equal(str, "true")
из Guavaили
StringUtils.equals(str, "true")
из commons lang +3
> Код с анонимными классами читается гораздо трудней и сложен для восприятия.
Ну я бы поспорил, это очень субъективно, и еще зависит от конкретного кода. Часто такие решения достаточно универсальны и красивы.
> String status = plan.getStatus();
> if (status.equals(«draft»)) {
Еще можно добавить, что это не только медленно, но и небезопасно, т.к. plan.getStatus() теоретически может вернуть null, и тогда огребем NPE при вызове equals().
Лучше сравнивать строки так:
«draft».equals(status)
Ну я бы поспорил, это очень субъективно, и еще зависит от конкретного кода. Часто такие решения достаточно универсальны и красивы.
> String status = plan.getStatus();
> if (status.equals(«draft»)) {
Еще можно добавить, что это не только медленно, но и небезопасно, т.к. plan.getStatus() теоретически может вернуть null, и тогда огребем NPE при вызове equals().
Лучше сравнивать строки так:
«draft».equals(status)
+7
Вот тут отличная подборка по подобным советам: www.odi.ch/prog/design/newbies.php
К слову. Автор кажется туда заглядывал.
К слову. Автор кажется туда заглядывал.
+1
Есть даже целые сайты javaantipatterns.wordpress.com/. Надо гуглить по запросу «java anti-patterns».
+3
По поводу name.isEmpty() — это появилось только в JDK 1.6. Безопасней будет либо сравнить с константой "", либо по аналогии name.lenght() == 0. Хотя второй вариант встречался реже
+1
А так как в 90% случаев надо среагировать и на null, и на "", то еще лучше использовать org.apache.commons.lang.StringUtils.isEmpty( s )
+6
UFO just landed and posted this here
>>Object[] vs custom Class
О боги, неужели вариант «плохо» ещё кто-то пишет? Это вообще диковинка какая-то)
За цикл статей — спасибо, уже пару полезных для себя мелочей заметил!
О боги, неужели вариант «плохо» ещё кто-то пишет? Это вообще диковинка какая-то)
За цикл статей — спасибо, уже пару полезных для себя мелочей заметил!
0
Да, я и сам иногда грешу =), но только когда очень спешу и проще и быстрей написать так. Когда например делается выборка 2-х колонок из разных таблиц.
0
Наверно, это последствия детской травмы, полученной программистом при изучении конструкторов С++
-2
Я пишу. Плачу, но пишу. Потому что в среде j2me приходится экономить память, а создание классов под то, что можно реализовать массивами — непозволительная роскошь.
Вернее, позволить-то можно себе. Но тогда проблемы вылезут в другом месте.
Вернее, позволить-то можно себе. Но тогда проблемы вылезут в другом месте.
+1
С первым пунктом я не согласен. Есть какой-то бенчмарк в подтверждение?
-4
public static void main(String args[]) throws IOException {
//~5mb
File file = new File("D:\\P1010387.jpg");
readFile(new BufferedInputStream(new FileInputStream(file)), "Buffered");
readFile(new FileInputStream(file), "Not buffered");
}
private static void readFile(InputStream is, String type) throws IOException {
System.out.println(type);
System.out.println("Start : " + new Date());
int val = 0;
while ((val = is.read()) != -1) {
val = val + 1;
}
System.out.println("End : " + new Date());
}
0
Хм, теоретически, ОС и сама может закешировать файл, и чтение всё-равно будет из памяти, но это будет зависит от конкретной джавамашины, ОС, настроек и фазы луны.
+2
Я поэтому и усомнился. ОС сама кеширует чтение из диска. Мне показалось сомнительным пытаться оптимизировать такие вещи на уровне Java.
0
Вот только на каждое чтение может происходить переключение контекста, поиск и проверка на допустимость хэнделера файла, поиск в кэше, вызов драйверов и т.п. Кроме того, ОС не знает будет ли произвольный или последовательный доступ к файлу и потому упреждающее чтение будет использоваться очень осторожно. Кроме того упреждающее чтение как правило работает только для нефрагметированных данных (гонять головки диска, чтобы прочитать данные без уверенности, что они могут понадобиться — дорогое удовольствие). В общем можно считать, что упреждающего чтения в ОС нет.
+2
isEmpty() касается и коллекций, поскольку далеко не все они хранят информацию о своем размере, а это ведет к необходимости полного перебора.
+1
Что касается файлового IO, правильно использовать java.nio.*, а не вникать в неудачные места устаревшего API.
-1
Очень зависит от окружения. Советую просмотреть вот эту штуку, а также вспомнить, какой шаг вперёд сделал Linux в многопоточности от 2.4 к 2.6.
+1
Правда, в этом случае есть один большой минус — стоимость поддержки приложения увеличивается, особенно это становится заметным, когда нужно добавить, удалить или изменить одно из существующих состояний.
Перечисления же модифицировать, наоборот, проще. Изменил в объявлении, и оно поменялось везде. А вот со строками придётся вручную искать все упоминания в коде и разбираться, нужно здесь менять, или это просто совпадение имён.
+3
В дополнение — постоянно при добавлении вычисляется хеш, который для сложных обьектов может стоить дороговато.
По умолчанию джава использует в качестве хеша что-то вроде адреса объекта в памяти, поэтому обычно генерироваться он будет быстро.
0
Для сложных объектов скорее всего будет сложный хеш. Причем, он еще в подавляющем большинстве случаев еще и не кэшируется и будет честно считаться каждый раз при работе с хешсетом.
+1
+1-1
Сложный хэш будет. Но считаться по канонам Java он должен лишь раз. В противном случае вы свой объект в том же Set'е никогда не найдёте.
Сложный хэш будет. Но считаться по канонам Java он должен лишь раз. В противном случае вы свой объект в том же Set'е никогда не найдёте.
0
Это не так. Попробуйте добавить объект в HashSet 2 раза и проверьте, сколько раз будет вызван метод hashCode. Ответ — 2 раза. Более того, если после добавления элемента в HashSet вы поменяете его состояние и этим измените hashCode, то получите шикарный баг. Итерируясь по коллекции вы сможете найти объект, но тем не менее contains вернет false (как раз таки объект вы не действительно найдете в HashSet) и добавить его можно будет еще раз, уже в другое место массива. Я собственно это в свое время и словил, ибо не понимал что HashMultimap слово Hash от HashSet, а не как я думал от HashMap. ArrayMultimap решил ту проблему.
HashSet[Object] q = new HashSet[Object]();
Object o = new Object() {
@Override
public int hashCode() {
System.err.println(«hashCode»);
return super.hashCode();
}
};
q.add(o);
q.add(o);
Тем не менее, кэшировать хэшкод это очень правильная идея в плане перформанса, но поддержка этого кэширования в коде слишком трудоемко для сложных случаев, где от кэша собственно и будет эффект, ибо кэш надо будет сбрасывать на любую мутацию объекта, в итоге не встречал, чтобы ктото хэш кэшировал на практике.
HashSet[Object] q = new HashSet[Object]();
Object o = new Object() {
@Override
public int hashCode() {
System.err.println(«hashCode»);
return super.hashCode();
}
};
q.add(o);
q.add(o);
Тем не менее, кэшировать хэшкод это очень правильная идея в плане перформанса, но поддержка этого кэширования в коде слишком трудоемко для сложных случаев, где от кэша собственно и будет эффект, ибо кэш надо будет сбрасывать на любую мутацию объекта, в итоге не встречал, чтобы ктото хэш кэшировал на практике.
-1
> в итоге не встречал, чтобы ктото хэш кэшировал на практике.
Все встречали.
java.lang.String. :)
Все встречали.
java.lang.String. :)
+1
Во-первых, вам стоит научится пользоваться дебаггером, это избавит от необходимости каждый раз вставлять System.out и перекомпилироваться.
Во-вторых, читать документацию. Стоит изучить так называемый «Общий контракт работы с хэш кодами» (The general contract of hashCode) из JDK.
Стоит также почитать всякие заметки, чтобы понять, что это делается не только для перформанса.
И в конце концов, читайте то, что вам собеседники пишут. Я описал то же самое, ожидая, что коллеги по цеху меня поймут.
>>В противном случае вы свой объект в том же Set'е никогда не найдёте.
>тем не менее contains вернет false
Ко всему прочему, изучите имплементацию HashSet, она построена не на массиве, и в комментариях тут это уже даже упоминалось.
Если не умеете перегружать хэш коды самостоятельно, воспользуйтесь Apache HashCodeUtil, построенной, как помню, на простых числах.
Во-вторых, читать документацию. Стоит изучить так называемый «Общий контракт работы с хэш кодами» (The general contract of hashCode) из JDK.
Стоит также почитать всякие заметки, чтобы понять, что это делается не только для перформанса.
И в конце концов, читайте то, что вам собеседники пишут. Я описал то же самое, ожидая, что коллеги по цеху меня поймут.
>>В противном случае вы свой объект в том же Set'е никогда не найдёте.
>тем не менее contains вернет false
Ко всему прочему, изучите имплементацию HashSet, она построена не на массиве, и в комментариях тут это уже даже упоминалось.
Если не умеете перегружать хэш коды самостоятельно, воспользуйтесь Apache HashCodeUtil, построенной, как помню, на простых числах.
0
1. По контракту хешкод обязан сохранять свое значение при условии, что информация используемая в equals не была обновлена. С-но, если же эта информация была обновлена, то хэш код изменится, и это не нарушает контракт хэш кода. Посмотрите javadoc к методу hashCode.
method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
2. HashSet построен на основе HashMap, который в свою очередь построен на основе массива.
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
3. HashCodeUtil или любой другой аналог, не поможет вам кэшировать хэш в мутабл объекте. Потому что этот кэш придется сбрасывать на любое изменение объекта. И вообще рекомендовать Apache Commons это неразумно, он застрял на уровне семантики явы 1.4 и его развитие неудовлетворительное. Есть отличный форк от него под названием Guava, в которой есть аналогичные метода, но уже с семантикой 6й явы, например, Objects.hashCode(...).
4. Вы написали, что хэш будет считаться по канонам явы один раз на объект. Это очевидно неправда.
HashMap:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
В самом начале метода put у HashMap у ключа тупо вызывается hashCode, на каждый put/add/contains итп будет вызван этот метод.
method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
2. HashSet построен на основе HashMap, который в свою очередь построен на основе массива.
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;
3. HashCodeUtil или любой другой аналог, не поможет вам кэшировать хэш в мутабл объекте. Потому что этот кэш придется сбрасывать на любое изменение объекта. И вообще рекомендовать Apache Commons это неразумно, он застрял на уровне семантики явы 1.4 и его развитие неудовлетворительное. Есть отличный форк от него под названием Guava, в которой есть аналогичные метода, но уже с семантикой 6й явы, например, Objects.hashCode(...).
4. Вы написали, что хэш будет считаться по канонам явы один раз на объект. Это очевидно неправда.
HashMap:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
В самом начале метода put у HashMap у ключа тупо вызывается hashCode, на каждый put/add/contains итп будет вызван этот метод.
0
У нас на проекте принято использовать для логгера
private Logger logger = Logger.getLogger(getClass());
опять же, несмотря на некоторую неэффективность данного подхода, зато очень удобно копипастить и нет глупых ошибок при этом.
И я бы наоборот советовал, везде где это возможно, инициализировать поля, там же где они объявлены. Код все еще чистый, и на одну строчку короче. Для того и предзначена эта возможность, чтобы не засорять этим конструктор.
private Logger logger = Logger.getLogger(getClass());
опять же, несмотря на некоторую неэффективность данного подхода, зато очень удобно копипастить и нет глупых ошибок при этом.
И я бы наоборот советовал, везде где это возможно, инициализировать поля, там же где они объявлены. Код все еще чистый, и на одну строчку короче. Для того и предзначена эта возможность, чтобы не засорять этим конструктор.
0
Про сериализацию. Я бы не советовал, без крайней нужды использовать стандартную ява сериализацию. Protobuf как правило намного более удобное решение. В принципе, вообще сильная связность объекта с его сериализацией, его компаратором или с его реализацией методов hashCode/equals как правило это плохая идея. Впрочем, по последнему пункту красивых решения я не встречал, поэтому все упирается во wrapper-декоратор объекты, которые просто перегружают методы hashCode/equals.
На самом деле это все большая проблема, потому что написать адекватный контейнер класс, который содержит 2 банальных стринг поля и по сути обычный pojo bean занимает у меня уже до 3х экранов кода, что конечно ужас. И, что печально, код везде повторяется, а вот без рефлекшена его вынести куда-то не выходит, а рефлекшен слабое решение с позиции перформанса, а вот для таких контейнеров как раз перформанс важен, ибо они обычно пролетают всю систему и несколько потоков меняют при этом.
На самом деле это все большая проблема, потому что написать адекватный контейнер класс, который содержит 2 банальных стринг поля и по сути обычный pojo bean занимает у меня уже до 3х экранов кода, что конечно ужас. И, что печально, код везде повторяется, а вот без рефлекшена его вынести куда-то не выходит, а рефлекшен слабое решение с позиции перформанса, а вот для таких контейнеров как раз перформанс важен, ибо они обычно пролетают всю систему и несколько потоков меняют при этом.
0
Толковая IDE может сама обновлять имя класса при копировании такой строчки.
0
По теме данной статьи можно почитать очень хорошую книгу Effective Java, автор Joshua Bloch. Там целая книга примеров правельного написания кода на Java.
Даже сам
Даже сам
+1
Почему еще никто не сказал про интернацию.
0
если бы один раз, но целых 3 раза, поэтому:
//плохо
стаття
//хорошо
статья
//плохо
стаття
//хорошо
статья
-1
www.odi.ch/prog/design/newbies.php — в копилку. анти-паттерны :)
0
>И еще — считывайте данные порциями, а не по байтам, это тоже позволит прилично сэкономить.
Считывание данных порциями (java.io.InputStream.read(byte b[], int off, int len)) реализовано как вызов побайтного считывания в цикле (java.io.InputStream.read()). :) 1.6.0_29
Так что морочиться этим не обязательно.
Считывание данных порциями (java.io.InputStream.read(byte b[], int off, int len)) реализовано как вызов побайтного считывания в цикле (java.io.InputStream.read()). :) 1.6.0_29
Так что морочиться этим не обязательно.
+1
Only those users with full accounts are able to leave comments. Log in, please.
Маленькие хитрости Java. Часть 2