Pull to refresh

Comments 91

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.

Я знаю, в C getchar() тоже int возвращает дабы была возможность детектировать ошибку.
Но всё равно выглядит очень странно такое название переменной и тип int.
int odin = 2; — как один тут товарищ писал, это странно, да :)
В С — как раз ничего странного. Где это возможно, используется тип int, т.к. он привязан к архитектуре процессора, под которую собран код — и обычно это максимально быстрая единица памяти, к которой имеет доступ процессор. Другими словами, экономия при объявлении переменной может обернуться либо тем же расходом памяти (в случае если компилятор их выровняет по границам, кратным размеру int), либо медленным доступом.
крошка сын к отцу пришел, и спросила кроха… :)
… Что такое singleton,
И что такое mockup?

:-)
> В случае явного указания значений для полей класса — они будут проинициализированы до вызова конструктора, что влечет дополнительные расходы.

Какие расходы? На что?
UFO just landed and posted this here
Интересный вариант, но стаття как раз про то как не нужно делать. Поэтому preconditions в конструкторе не очень хороший вариант =).
UFO just landed and posted this here
Если исходить из Ваших условий — приватный конструктор и статический метод в классе, который осуществит нужные проверки и вернет корректный обьект или ошибку.
UFO just landed and posted this here
Шаблон «фабрика» спешит на помощь.
Я знал, что обязательно кто-то это подметит. Шаблоны тем не менее не всегда уместны. На хабре была стаття по этому поводу.
Шаблоны уместны там, где они… уместны.
И проверка всяких условий перед фактическим созданием объекта — как раз одно из мест, где применение шаблона «фабрика» просто напрашивается.
Тоесть для этого примера я должен был бы создать шаблон «фабрика»?
Боюсь вам разочаровать, но шаблон «абстрактная фабрика» был создан и описан умными бородатыми дядьками в умной тонкой книжке почти двадцать лет назад…
Вы трижды одинаково опечатались в слове «статья». Это настораживает
Я думаю на украинском. Извиняюсь, буду исправляться
UFO just landed and posted this here
В случае если вы создаете обьект с пустым конструктором и инициализация полей Вам не нужна. А в пределах приложения это может быть существенно. В любом случае Вы правы, этот момент нужно подправить.
Например на

private List zzz = new ArrayList();
А разница с тем, что он создастся в констукторе?
Например в конструкторе может быть дополнительная логика, которая будет менять/отменять инициализацию либо выполнять инициализацию полей более эффективным способом.

Пример: конструктор принимает список элементов, эффективней будет сделать zzz = new ArrayList(providedValues), чем вначале просто проинициализировать список, а потом добавить в него элементы.
UFO just landed and posted this here
Быть может повторюсь, но тем не менее.
Есть еще полезный прием:

"true".equals(str)

Позволяет избежать NPE при сравнении строк с константами.
В принципе — да… Тем не менее 90% случаев сравнения строк — это
label.equals(str)

Этот случай больно уж редкий.
Не очень удачный пример, конкретно в данном случае лучше Boolean.valueOf(str);
Но для других, нестандартных строк, действительно хороший вариант.
Так же очень удобно использовать null-safe

Objects.equal(str, "true") из Guava

или

StringUtils.equals(str, "true") из commons lang
>Objects.equal(str, «true») из Guava

В 7ке появился java.util.Objects. Не 1 в 1 с тем, что в Guava, но для equals/compare годится.
> Код с анонимными классами читается гораздо трудней и сложен для восприятия.

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

> String status = plan.getStatus();
> if (status.equals(«draft»)) {

Еще можно добавить, что это не только медленно, но и небезопасно, т.к. plan.getStatus() теоретически может вернуть null, и тогда огребем NPE при вызове equals().
Лучше сравнивать строки так:

«draft».equals(status)
>>Ну я бы поспорил
Я ведь написал — в некоторых ситуациях очень применимы.
Здесь предполагалось что часть модели Plan.status не может быть null. В виду constraint БД.
UFO just landed and posted this here
Потому что это не 7-я Java. Старые проекты врятли уже когда-нибудь перейдут на 7-ю.
UFO just landed and posted this here
В проекте так и сделано, это просто для примера.
> Надо гуглить по запросу «java anti-patterns».

Категорически плюсую, очень интересные и неочевидные вещи попадаются. Еще добавлю в копилку слов для гугления полезных советов — «java exceptions anti-patterns».
По поводу name.isEmpty() — это появилось только в JDK 1.6. Безопасней будет либо сравнить с константой "", либо по аналогии name.lenght() == 0. Хотя второй вариант встречался реже
А так как в 90% случаев надо среагировать и на null, и на "", то еще лучше использовать org.apache.commons.lang.StringUtils.isEmpty( s )
Да, полностью с вами согласен. Обычно используем либо StringUtils.isEmpty либо StringUtils.isBlank в зависимости от ситуации. Я привел пример без использования внешних библиотек.
UFO just landed and posted this here
UFO just landed and posted this here
>>Object[] vs custom Class
О боги, неужели вариант «плохо» ещё кто-то пишет? Это вообще диковинка какая-то)
За цикл статей — спасибо, уже пару полезных для себя мелочей заметил!
Да, я и сам иногда грешу =), но только когда очень спешу и проще и быстрей написать так. Когда например делается выборка 2-х колонок из разных таблиц.
Даже если спешить, в любой IDE класс с public полями сделать не намного медленнее, чем Object[]. А читать на порядок проще.
Наверно, это последствия детской травмы, полученной программистом при изучении конструкторов С++
Я пишу. Плачу, но пишу. Потому что в среде j2me приходится экономить память, а создание классов под то, что можно реализовать массивами — непозволительная роскошь.
Вернее, позволить-то можно себе. Но тогда проблемы вылезут в другом месте.
С первым пунктом я не согласен. Есть какой-то бенчмарк в подтверждение?
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());
	}
Ужас. new Date()?

Есть же System.currentTimeMillis();
Хм, теоретически, ОС и сама может закешировать файл, и чтение всё-равно будет из памяти, но это будет зависит от конкретной джавамашины, ОС, настроек и фазы луны.
Я поэтому и усомнился. ОС сама кеширует чтение из диска. Мне показалось сомнительным пытаться оптимизировать такие вещи на уровне Java.
Вот только на каждое чтение может происходить переключение контекста, поиск и проверка на допустимость хэнделера файла, поиск в кэше, вызов драйверов и т.п. Кроме того, ОС не знает будет ли произвольный или последовательный доступ к файлу и потому упреждающее чтение будет использоваться очень осторожно. Кроме того упреждающее чтение как правило работает только для нефрагметированных данных (гонять головки диска, чтобы прочитать данные без уверенности, что они могут понадобиться — дорогое удовольствие). В общем можно считать, что упреждающего чтения в ОС нет.
Для меня полное откровение, уверен был, что на упреждающее чтение можно смело наедятся. Где можно про это поподробнее узнать?
isEmpty() касается и коллекций, поскольку далеко не все они хранят информацию о своем размере, а это ведет к необходимости полного перебора.
А какие — не хранят?
UFO just landed and posted this here
Size дорого, но isEmpty уже не так дорого.
Для isEmpty достаточно проверить, есть ли хоть один элемент. Это практически в любом случае делается за фиксированное время.
Что касается файлового IO, правильно использовать java.nio.*, а не вникать в неудачные места устаревшего API.
Очень зависит от окружения. Советую просмотреть вот эту штуку, а также вспомнить, какой шаг вперёд сделал Linux в многопоточности от 2.4 к 2.6.
Правда, в этом случае есть один большой минус — стоимость поддержки приложения увеличивается, особенно это становится заметным, когда нужно добавить, удалить или изменить одно из существующих состояний.

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

По умолчанию джава использует в качестве хеша что-то вроде адреса объекта в памяти, поэтому обычно генерироваться он будет быстро.
Для сложных объектов скорее всего будет сложный хеш. Причем, он еще в подавляющем большинстве случаев еще и не кэшируется и будет честно считаться каждый раз при работе с хешсетом.
+1-1
Сложный хэш будет. Но считаться по канонам Java он должен лишь раз. В противном случае вы свой объект в том же Set'е никогда не найдёте.
Это не так. Попробуйте добавить объект в 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);

Тем не менее, кэшировать хэшкод это очень правильная идея в плане перформанса, но поддержка этого кэширования в коде слишком трудоемко для сложных случаев, где от кэша собственно и будет эффект, ибо кэш надо будет сбрасывать на любую мутацию объекта, в итоге не встречал, чтобы ктото хэш кэшировал на практике.
> в итоге не встречал, чтобы ктото хэш кэшировал на практике.
Все встречали.
java.lang.String. :)
Immutable это нечестно, такое встречал конечно и не раз. :)
Во-первых, вам стоит научится пользоваться дебаггером, это избавит от необходимости каждый раз вставлять System.out и перекомпилироваться.

Во-вторых, читать документацию. Стоит изучить так называемый «Общий контракт работы с хэш кодами» (The general contract of hashCode) из JDK.

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

И в конце концов, читайте то, что вам собеседники пишут. Я описал то же самое, ожидая, что коллеги по цеху меня поймут.
>>В противном случае вы свой объект в том же Set'е никогда не найдёте.
>тем не менее contains вернет false

Ко всему прочему, изучите имплементацию HashSet, она построена не на массиве, и в комментариях тут это уже даже упоминалось.

Если не умеете перегружать хэш коды самостоятельно, воспользуйтесь Apache HashCodeUtil, построенной, как помню, на простых числах.
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 итп будет вызван этот метод.

У нас на проекте принято использовать для логгера
private Logger logger = Logger.getLogger(getClass());
опять же, несмотря на некоторую неэффективность данного подхода, зато очень удобно копипастить и нет глупых ошибок при этом.

И я бы наоборот советовал, везде где это возможно, инициализировать поля, там же где они объявлены. Код все еще чистый, и на одну строчку короче. Для того и предзначена эта возможность, чтобы не засорять этим конструктор.
Про сериализацию. Я бы не советовал, без крайней нужды использовать стандартную ява сериализацию. Protobuf как правило намного более удобное решение. В принципе, вообще сильная связность объекта с его сериализацией, его компаратором или с его реализацией методов hashCode/equals как правило это плохая идея. Впрочем, по последнему пункту красивых решения я не встречал, поэтому все упирается во wrapper-декоратор объекты, которые просто перегружают методы hashCode/equals.
На самом деле это все большая проблема, потому что написать адекватный контейнер класс, который содержит 2 банальных стринг поля и по сути обычный pojo bean занимает у меня уже до 3х экранов кода, что конечно ужас. И, что печально, код везде повторяется, а вот без рефлекшена его вынести куда-то не выходит, а рефлекшен слабое решение с позиции перформанса, а вот для таких контейнеров как раз перформанс важен, ибо они обычно пролетают всю систему и несколько потоков меняют при этом.
Толковая IDE может сама обновлять имя класса при копировании такой строчки.
Intellij Idea/Eclipse не умеют.
Как раз-таки Idea умеет. Насчет Eclipse не знаю.
И как этим пользоваться? Если просто скопировать, то 10.5.2 Idea не правит название класса. Тут есть какой-то хинт?
По теме данной статьи можно почитать очень хорошую книгу Effective Java, автор Joshua Bloch. Там целая книга примеров правельного написания кода на Java.

Даже сам
Даже сам James Gosling (fellow and vice president, Sun Microsystems, Inc., and inventor of the Java programming language) писал об этой книге:
I sure wish I had this book ten years ago. Some might think that I don’t need any Java books, but I need this one.
Почему еще никто не сказал про интернацию.
Тут очень интересный ответ, поэтому не добавлял.
Деградация после 25к элементов — не новость.
Если Вам нужно запихнуть столько строк в пул — где-то что-то делаете не так. Для констант и сравнения интернация весьма полезна.
если бы один раз, но целых 3 раза, поэтому:

//плохо
стаття
//хорошо
статья
>И еще — считывайте данные порциями, а не по байтам, это тоже позволит прилично сэкономить.

Считывание данных порциями (java.io.InputStream.read(byte b[], int off, int len)) реализовано как вызов побайтного считывания в цикле (java.io.InputStream.read()). :) 1.6.0_29

Так что морочиться этим не обязательно.
Sign up to leave a comment.

Articles