Java на каждый день и не только. Рекомендации по использованию

Original author: Tomasz Nurkiewicz
  • Translation
Всем привет!

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



image
Java — это язык с мощными стандартными возможностями, но «Большая сила налагает большую ответственность». Я видел много java-кода, в котором чрезмерно (и зачастую — неправильно) использовались «редкие» свойства языка, в то время как основы основ были почти полностью проигнорированы. Эти наблюдения и послужили стимулом к написанию статьи.

Это не список обязательных к использованию каждым программистом особенностей языка. Скорее наоборот. Я разделил их на 3 группы: "для каждодневного использования", "для периодического использования" и "только для фреймворков и библиотек!". Правило простое: если вы понимаете, что используете указанные свойства чаще, чем рекомендуется, то, скорее всего, ваш код развивается по неправильному пути. Если же наоборот — вы редко используете какие-то свойства, чем я рекомендую, значит вы упускаете какие-то интересные и важные возможности языка.

Обратите внимание, что я говорю о разработке типичных серверных бизнес-приложений (JVM, JDK, вот это все) и не даю рекомендаций относительно каких бы то ни было фреймворков.

Для каждодневного использования


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

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

ExecutorService, thread pool
Нужно обязательно понимать и правильно использовать пулы потоков, очередей и объектов типа Future<T> Не изобретайте велосипедов, реализуя собственные пулы. Они должны в первую очередь приходить вам в голову, когда вы слышите о Producer-Consumer

Семейство Atomic-*
Не используйте synchronized для чтения/изменения счетчиков и ссылок. Семейство Atomic-* весьма эффективно реализовано на основе «сравнения с обменом» Убедитесь, что вы понимаете гарантии, которые предоставляют эти классы.

Шаблоны проектирования
Технически они не являются частью языка Java, но я обязан упомянуть о них в виду их важности. Вы должны знать, понимать и свободно использовать их, но в разумных пределах. (Так же как и интерфейсы, к слову). Шаблоны «Банды четырёх» и корпоративных приложений должны быть широко представлены в вашем коде. Но их использование должно подчиняться нуждам вашего приложения, а не наоборот.

Стандартные коллекции, в том числе многопоточные
Вам абсолютно необходимо знать и использовать встроенные коллекции, понимать разницу между List, Map и Set. Использование потокобезопасных реализаций также не должно быть проблемой. Нужно знать основные характеристики производительности и иметь представление о деталях реализаций. Добавим сюда же знание различных реализаций BlockingQueue. Параллельные вычисления и без того сложны, нужно пользоваться имеющимися средствами языка, а не изобретать свои велосипеды.

Встроенные аннотации
Они уже здесь и это надолго, поэтому смело пользуйтесь @Override и не забывайте про @Deprecated

Исключения
Используйте непроверяемые исключения (RuntimeExceptions) для сообщении об ошибках и ненормальных состояниях системы, когда требуется явная реакция на происходящее. Учитесь жить с проверяемыми исключениями. Учитесь читать стек-трейсы.

try-with-resources
Познакомьтесь с этой замечательной конструкцией. Реализуйте AutoCloseable, если вашему классу требуется освобождать ресурсы после завершения своей работы.

Блокирующий ввод/вывод
Пользуйтесь классами Reader/Writer, InputStream/OutputStream. Осознавайте в чем отличия между ними, смело используйте буферизацию и другие декораторы.

На этом список «на каждый день» заканчивается. Если вы о чем-то не слышали вовсе или слышали краем уха — изучите, вам это обязательно пригодится.

Для периодического использования


Описанные далее свойства Java можно и нужно использовать, но без фанатизма. Если вы каждый день уже до обеда успеваете применить что-то из этого раздела — с архитектурой вашего приложения определенно что-то не так. Повторюсь — с точки зрения разработчкика back-end эти вещи бывают полезны, но редко.

Наследование и абстрактные классы
Честно, я редко пользуюсь наследованием и не скажу, что сильно скучаю по нему. Полиморфизм весьма гибко реализуется на основе интерфейсов, особенно с учетом всех недостатков абстракции в Java(*) Также я предпочитаю наследованию композицию. Слишком большие иерархии порождают трудно поддерживаемый код
image

Регулярные выражения
Некоторые программисты, когда встречаются с проблемой, думают «О, я воспользуюсь регулярными выражениями!» И получают две проблемы. Мир без регулярных выражений был бы гораздо более скучным и громоздким. Они прекрасно подходят для парсинга регулярных множеств (кроме HTML), но опять же — с ними очень легко переусердствовать. Если вы целыми днями оперируете регулярными выражениями, вы выбрали неправильный инструмент. Хит всех времен:
public static boolean isNegative(int x) {
    return Integer.toString(x).matches("-[0-9]+");
}

Semaphore, CountDownLatch, CyclicBarrier и т.д.
Эти классы, конечно, на порядок более полезные, чем печально известная парочка wait()/notify(). Но и они не защищают вас от ошибок при использовании многопоточности. Если вы часто используете этот механизм для синхронизации — самое время посмотреть в сторону потоко-безопасных коллекций или специализированных фреймворков.

Параметризованные типы (generics) в пользовательском коде
Вообще использование встроенных коллекций и других типов данных, поддерживающих параметризацию — обычное дело для программиста. Но здесь я говорю об использовании параметризации в вашем собственном коде, когда ваши методы принимают или возвращают generic types. Например:
public <T, F> ContractValidator<T extends Contract> T validate(Validator<T>, F object)

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

Скриптовые языки в JVM
Знаете ли вы, что JDK имеет встроенный интерпретатор JavaScript? И что вы можете на лету подключить другие языки, вроде Groovy и JRuby? В век стремительно меняющихся рынков порой не хватает времени даже на то, чтобы передеплоить приложение, и внедрение небольшого скрипта с возможностью его редактирования конечным пользователем бывает хорошей идеей. Но помните, что если количество скриптов превышает 1% от общего количества строк в системе, вам нужно быть готовым к трудностям при поддержке.

Java NIO
Сложно использовать его правильно и ещё сложнее действительно получить от него выгоду. Иногда вы должны его использовать, чтобы выжать максимум по производительности и масштабированию. Но лучше все-таки пользоваться специализированными библиотеками, тем более что в большинстве случаев вполне достаточно обычного ввода-вывода.

synchronized
Не нужно злоупотреблять им по простой причине — чем больше таких блоков, тем чаще они выполняются и тем ниже производительность. Плюс всегда нужно быть хорошо уверенным в том, какой именно объект является мьютексом. Лучше используйте thread-safe коллекции и Atomic-*.

Итак, я считаю перечисленные в этом разделе свойства языка важными и полезными, но не необходимыми для каждодневного использования. Если вы пользуетесь ими постоянно — это признак перегруженной архитектуры… либо неопытного разработчика. Способность упрощать приходит с опытом. Но если к вашей системе предъявляются какие-то особенные требования — тогда самое время перейти к третьей группе.

Только для разработчиков фреймворков и библиотек!


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

сокеты
да-да, вы не ослышались, именно сокеты. Вы должны понимать как работает стек TCP/IP, сессии, потоки, уметь правильно интерпретировать данные. Но избегайте прямой работы на сетевом уровне. Существуют сотни высокоуровневых библиотек для HTTP, FTP, NTP, SMB, e-mail… взять тот же Apache Commons net. Вы вряд ли подозреваете, насколько сложно написать приличный HTTP клиент или сервер. А если вам нужен сервер для какого-то собственного протокола — я рекомендую ознакомиться с Netty

reflection
В прикладном коде нет места работе на уровне внутреннего устройства классов и методов. Это жизненно необходимо фреймворкам, но совершенно не нужно лично мне. Reflection делает ваш код низкоуровневым, небезопасным и просто… неприятным. АОР решает большинство проблем. Я бы даже сказал, что простая работа с экземплярами типа Class<?> уже «плохо пахнет».

динамические прокси и работа с байт-кодом
Proxy — это здорово, но, как и reflection, лучше оставить работу с ним на откуп фреймворкам и библиотекам. Прокси — основа построения легковесного АОР. Если ваше бизнес-приложение непосредственно работает с байт-кодом(**) (например через ASM или CGLIB) — вы в ж*пе мне остается только молиться за вас.

classloaders
… и все что с ними связано — в топку! опять таки — нужно понимать, как они работают, иерархию, байткод и т.д. Но если вы пишете свой загрузчик — это дорога в ад. Не то чтобы это было так сложно, но просто зачем? Пусть этим занимаются сервера приложений.

Object.clone()
Не помню, использовал ли я хоть раз этот метод за всю свою практику. А, вспомнил — совершенно точно ни разу не использовал! И даже не могу придумать, зачем он мне может понадобиться. Предпочитаю явные конструкторы копирования, а ещё лучше — неизменяемые объекты. А вам нужен именно clone? Похоже, кто-то застрял в девяностых…

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

самописные коллекции
правильно реализовать коллекцию в соответствии со всеми контрактами оригинального JavaDoc (внезапно) непростая задача Hibernate использует собственные реализации, но зачем они могут понадобиться вам — я не знаю.

ThreadLocal
Фреймворки и библиотеки используют эту технику довольно часто, но вы должны избегать этого по двум причинам. Первая — под маской ThreadLocal часто скрывается эдакая полу-глобальная переменная. Это усложняет понимание и тестирование кода. Вторая — ThreadLocal порождает утечку памяти в случае некоректной очистки. Для примера читаем тут, тут, тут и ещё вот тут и так далее…

WeakReference и SoftReference
Эти классы достаточно низкоуровневые и хорошо подходят для реализации кэшей, плотно интегрированных со сборщиком мусора. К счастью, существует множество open-source библиотек для подобных кэшей, так что нет нужды писать ещё один самостоятельно. Достаточно просто знать, что такие классы есть и представлять, как они работают.

Пакеты com.sun.* и sun.*, особенно sun.misc.Unsafe
Держитесь подальше от торфяных болот этих пакетов, потому что… да просто подальше и все! Это сугубо специальные, недокументированные классы без гарантии сохранения обратной совместимости в будущем. Просто представьте, что их нет. Да и зачем бы вам мог понадобиться Unsafe?

Собственно, на этом все. Конечно, все это моё абсолютнейшее ИМХО. Если вы чувствуете, что что-то не на своем месте, либо я забыл о чем-то существенном — прошу в комментарии, чтобы в дальнейшем я мог составить некое справочное руководство для проведения code-review или для помощи в оценке проекта.




(*) приветствуется более точный перевод выражения "a painful lack of traits in Java"
(**) пассаж про Mockito я тоже не осилил
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 68

    +5
    Ну а чо? Молодец. В целом верно.
      +5
      Сколько комплексов и насаждений чужих мыслей. Не статья, а — морализаторство на тему программирования.

      Думайте свой головой. Опыт придёт со временем. И он будет гораздо лучше того, что здесь тезисно описан.
        +1
        Когда будет опыт, то да. Но часто начинающие начинают лепить такое месиво из рефлексии, многопоточности и замудреной иерархии, что черт ногу сломит…
          +1
          Как «налепит», так и выкинет, думая своей головой. В противном случае привыкнет, что за ним придут другие и будут поддерживать всё его творение. Научиться сначала видеть и прогнозировать жизненный цикл результатов своего труда — это на начальном этапе поважнее «морализаторства» на тему как писать нужно и не нужно.
            +1
            Напишет и уйдет, кому-то поддерживать. Такой способ может и нормален, если человек сам по себе работает.
            Учиться на своих ошибках можно, но это дорого.
            0
            Такие статьи мало что дают новичкам.
            Как правило — прививание чужого мнения и, как следствие, перекрытие своего личного опыта этим самым «авторитетным» мнением.
            Поэтому братья за подобные измышления всерьез имеет смысл только в том случае, если Вы действительно хотите написать полноценный, качественный труд, рецензированный и одобренный профессионалами, редакторами и т.д. и т.п.
            Вы не поверите, очень многие программисты среднего и чуть выше среднего уровня знают по своему опыту все то, что Вы можете предложить в такой вот короткой форме, без конкретных сравнений «за» и «против» в каждом отдельном случае. А программистам низкого уровня категорически не советую читать подобные статьи. Лучше воспользоваться авторитетным источником — там гораздо более полно и толково описано, и при этом поясняется, почему — а именно это понимание и нужно новичкам.
              0
              >>Такие статьи мало что дают новичкам.
              Как минимум, они дают направление. Например, когда человек с опытом разработки N лет, не знает элементарных практик, так как не читал ни книг, ни статей, не обменивался опытом (варился в «своем соку»), потому как не знал обо всем этом — «справочная» инф. может дать хороший толчок в правильном направлении.

              >>что Вы можете предложить в такой вот короткой форме
              Это не моя статья и не мой перевод…
              0
              И правильно, в общем, делают. Надо упражняться и осваивать. Лучше, правда, «не за счёт меня», но тут так или иначе «кому-то придётся быть первым».
            +2
            Отличная статья.
            Про мокито, я бы так перевел:
            >>If your business application (not framework or library, even Mockito uses these techniques!) requires byte code generation or manipulation (e…
            Если ваше бизнес-приложение (не фреймворк или библиотека, как раз Mockito использует эту технику!) требует генерации байт-кода или манипуляции с ним (напр…
              +1
              >>a painful lack of traits in Java
              тут, видимо, имеется ввиду типаж (traits, трейты )
              Перевод: ", особенно ввиду болезненного отсутствия трейтов в Java"
                0
                Желающие trait'ов, кстати, могут радоваться — некоторое их подобие будет в Java 8 (default-методы в интерфейсах).
                +1
                спасибо за перевод
                  +10
                  <facepalm>
                  Для каждодневного использования

                  Шаблоны проектирования
                  Семейство Atomic-*

                  Для периодического использования

                  Наследование и абстрактные классы
                  </facepalm>

                  Программистов с шаблонометом к коду подпускать не то что на пушечный выстрел нельзя, их надо истреблять в раннем детстве из рогатки. Хромают ваши рекомендации.
                    0
                    Наследование ломает контракт. Если другие классы воспринимают родительский класс как набор публичных методов, то классу потомку открывается реализация, что бывает нужно далеко-далеко не всегда.
                      +1
                      Для контрактов существуют интерфейсы.
                      0
                      Шаблоны проектирования — это печальное следствие не-функциональности языка программирования. Когда блок кода нельзя передать как параметр, приходится копипастить «обвязку» для него. Если бы не это, шаблоны проектирования выродились бы в библиотечные функции или вообще в идиомы языка программирования, как шаблон «стратегия» в языке Java.
                      +6
                      «Да-да, размещайте свой код в классах» — да, это классная рекомендация. Еще бы знать, как можно разместить код вне класса.

                      Наследование, абстрактные классы и дженерики — это как раз для постоянного использования. Видимо, автор еще не освоил эти темы, и подсознательно пытается себя оправдать.
                        +1
                        >Еще бы знать, как можно разместить код вне класса.

                        Я так понял, автор имел в виду, что классы без логики и классы без данных — это не «настоящие» классы. И рекомендует использовать именно канонические, с логикой и данными.
                        –3
                        а что, правда WeakReference и SoftReference в бизнес-логике не нужны? оО
                          +9
                          Редкостная чушь.

                          Такое чувство, что совсем молодой иностранный специалист написал свои первичные соображения после относительно непродолжительного использования Java. Абстрактные классы оказывается есть вещь второй важности. Как и наследование с generics. :)

                          А наш человек старательно перевёл это, ибо полагает, что всё что пишет иностранец — есть круто по определению. Как при Петре 1. Этот молодой иностранный парень имеет право писать всё что хочет в своём блоге. Но к чему это распространять?

                          Если кто-то считает, что оригинальный автор уже силён в разработке, откройте по ссылке его блог и ужаснитесь как это всё забавно выглядит. :)

                            +1
                            Я согласен с тем что статья — «Редкостная чушь.», но все же в чем я согласен с автором статьи — в отношении к абстрактным классам.
                            Как бы периодически занимаясь review кода коллег понимаешь, что этот паттерн как правило применяется крайне неудачно — в лучшем случае код не получает бенефитов от наследования, в худшем — получает существенные минусы. Связано с тем что люди часто используют абстрактные классы тогда, когда их можно было бы успешно заменить композицией, что плохо
                              +1
                              Абстрактный класс не является паттерном. Абстрактный класс, это синтаксическая возможность языка объявить некий служебный класс (который не может инстанциироваться), который может быть воткнут в иерархию между интерфейсом и полной его, интерфейса, реализацией, дабы застолбить базовую реализацию некоторых методов. Может служить заменой интерфейсу (и служит, скажем, в с++). Никакого отношения к композиции он не имеет. Выбор между наследованием и композицией это немножко из другой оперы.
                                0
                                Если в каких-то кусках кода можно выделить общие черты, значит это паттерн. Это единственное логичное определение, в конце концов, вы же не считаете что «паттерн» это все что было упомянуто в трех-четырех книжках, в названии которых встречается слово «паттерн»?
                                Ну и собственно суть моего поста, к которому вы возразили, была в том, что абстрактные классы часто применяются не в тему, по крайней мере по моим наблюдениям.
                                Не нравится называть это паттерном, можете называть хоть артишоком.
                                  0
                                  Абстрактный класс реализуется на уровне синтаксиса языка. Туда выносится код, который потенциально будет общим и полезным для большого количества наследников. Просто общий код класса можно в любой метод вынести.

                                  Логически, постулирование некоего класса как абстрактный, конечно же можно назвать паттерном. Но в «быту», его таковым уже не называют, в силу того, что он давно перешёл в разряд тривиально естественных и полезных вещей, ценность которых давно не оспаривается.
                                    –3
                                    > Туда выносится код, который потенциально будет общим и полезным для большого количества наследников

                                    О, господи. Т.е. наличие общего кода между наследниками означает, что нужно кидаться выделять некий абстрактный класс, который бы этот код содержал? Извините, но из-за таких как вы и возникают совершенно бессмысленные и перегруженные иерархии классов. Вы просто не понимаете, зачем нужно наследование.
                                      0
                                      А из-за таких как вы на проекте начинается паника на ровном месте. :)

                                      Бездумно кидаться и что-то там лихорадочно «выделять» вобще в жизни никогда не нужно, Везде нужно вначале думать.

                                      А абстрактный класс действительно позволяет собрать в одно место те базовые реализации методов, которые будут полезны потомкам. Видя, что некий метод имеет реализацию в абстрактном классе, вы уже знаете, что скорее всего эта реализация закрывает большинство потребностей и вам самим её делать не нужно. Опять же, на уровне абстрактного класса происходит некое внутреннее структурирование методов (интерфейс то ведь содержит только видимые паблик методы). Таким образом, вы сразу видите ту логику, которую желательно разнести по разным методам. Опять же, чётко выделяются те методы, которые вы просто обязаны реализовать.
                                      Таким образом, абстрактный класс позволяет организовать код логически более понятно и безопасно. Ни к какой перегруженности иерархии эта возможность сама по себе не ведёт. Иерархию можно легко сделать избыточной и не имея возможности постулировать класс абстрактным.
                                        0
                                        > А абстрактный класс действительно позволяет собрать в одно место те базовые реализации методов, которые будут полезны потомкам

                                        Это все следствие. Нужно понимать саму суть наследования. Применять абстрактные классы нужно тогда, когда действительно между потомком и родителем есть отношение «is». Пролистайте, пожалуйста, презентацию www.slideshare.net/biBIGine/agile-7158754 (слайды 62-75). Там описаны примеры неправильного использования наследования. Если вы согласны с тем, что там написано, значит мы просто спорим об одном и том же, но говорим на разных языках
                                          0
                                          Вот к чему вы мешаете в одну кучу понятие абстрактного класса и сам общий принцип наследования?

                                          Вот эта ваша фраза:… Применять абстрактные классы нужно тогда, когда действительно между потомком и родителем есть отношение «is»… она звучит странно, ибо касается не непосредственно абстрактных классов, а постулирует принцип использования наследования как приём проектирования в целом. И причём тут это?

                                          Когда мы создаём абстрактный класс, мы предполагаем, что в этой части проекта наследование УЖЕ выбрано как удобный и подходящий подход. Правильно это было сделано или нет, но это проектное решение другого уровня.

                                          Абстрактный же класс (как выразительная особенность языка) позволяет определить наследование более безопасно и понятно.
                                            0
                                            Моя цепочка суждений такова: абстрактные классы — это базовые классы (абстрактные классы без наследников бессмысленны, не правда ли?). Базовые классы выделяются тогда, когда есть отношение «частное-общее» + общее само по себе не бесполезно (т.е. например, если есть программа, в которой все объекты — это кошки, то бессмысленно выделять класс Животное, если оно ни в одном месте в коде не будет использоваться). Так вот, такое правильное отношения наследования, на самом деле, встречается довольно редко (по моему опыту). А значит, абстрактные классы нужно применять очень умеренно, о чем и говорит автор статьи.
                                              +1
                                              Угу. Если у них есть есть абстрактный класс, то поди и наследование присутствует. А раз присутствует наследование, то значит они ж его, стопудов, неправильно сделали. Прочту-ка и им лекцию на всякий случай на будущее…

                                              Муж жене:
                                              — Дорогая, ты не права.

                                              — Мама, он меня сукой обозвал!!!
                                                0
                                                Мне показалось, что вы не понимаете сути наследования, вот и «прочитал лекцию». Вы же, кстати, никак не защитили свой тезис о том, что абстрактные классы — вещь первой важности. Наехали на автора, а доводов никаких не привели
                                                  0
                                                  Перечитайте внимательно. Я пояснил для чего они нужны. И да, если я принял решение об использовании наследования, то далее решаю не вынести ли что-то в абстрактный класс.
                                                  На основании чего вы решили, что я не понимаю сути наследования, мне осталось непонятным.
                                                    0
                                                    Вы пояснили, для чего они нужны. Но не пояснили, почему не прав автор.
                                                      0
                                                      Вот именно — я пояснил для чего они нужны. А вот автор не пояснил, а посоветовал типа не использовать часто. Глубокий такой совет… :)
                                                        0
                                                        Ну т.е. проблема в том, что он не расписал более подробно. Это да
                                        0
                                        А что, тогда, по Вашему мнению делать с принципом DRY? Делегировать?
                                          0
                                          Вы можете сами ответить на свой вопрос. Есть два класса, совершенно никак не связанных друг с другом. Так получилось, что у них есть общий код. Что вы в этом случае сделаете? Выделите общую функциональность в синтетический базовый абстрактый класс, который по своей сути лишен смысла и нигде в проекте не будет фигурировать как отдельная сущность?
                                            +1
                                            И что с того, что у них общий код? С чего вы решили, что все вокруг такие балваны, что из-за общего кода сразу бросаются городить иерархию классов, и вам непременно нужно начать крайне решительно с этим бороться? :D
                                              0
                                              > все вокруг такие балваны
                                              Так вот именно, что полные болваны. В университете людям прочитали курс, в котором было сказано, что «Туда выносится код, который потенциально будет общим и полезным для большого количества наследников». А про то, что надо думать головой, не было сказано ничего. Вот и выносят что попало в базовые классы. Проект пухнет от десятиуровневой иерархии наследования, и хочется кого-нибудь пристрелить.
                                                0
                                                Бывает и такое, но в данном-то случае речь шла совсем о другом. Не так-ли? Посему и не понятно к чему вы нам лекцию о правильном употреблении наследования решили вдруг прочесть. :)
                                                  0
                                                  Речь изначально шла о частоте применения абстрактных классов. Я утверждаю, что это частота обусловлена лишь тем, что люди просто-напросто втыкают эти абстрактные классы где попало. На самом же деле, если бы они применяли абстрактные классы только там, где это действительно необходимо, то тогда эта частота резко бы уменьшилась. А это означает, что ваше мнение о статье как о «редкостной чуши», все-таки несколько гиперболизировано, не находите? Разве не прав в том, что наследование нужно применять крайне осторожно?

                                                  Цитата:

                                                  «Для периодического использования
                                                  Описанные далее свойства Java можно и нужно использовать, но без фанатизма»

                                                  Разве вы не согласны с этим?
                                                    +1
                                                    Я не руководствуюсь критериями типа «с фанатизмом», «без фанатизма»…

                                                    Нужно, буду использовать. Не нужно — не буду. Если нужно — буду использовать столько сколько нужно. Фанатизм тут не причём. Я фанатизмом нигде не руководствуюсь и абстрактные советы типа… используйте но без фанатизма… полезными не считаю.
                                                      0
                                                      А как вы определяете, что это нужно, а то не нужно? Проектирование — вещь грязная: один программист может сделать отличную программу одним способом, другой — тоже отличную программу совершенно по-другому. Первый может каждый второй класс сделать дженериком, второй — вообще их не использовать. Нету однозначного критерия «правильно — неправильно»
                                      +1
                                      'has a' and 'is a'
                                      Дом является Строением — используем наследование.
                                      Дом обладает ванной — используем композицию.

                                      Субъективно, наследование делает код сложночитаемым и плохо поддерживаемым.
                                      Особенно если принципы дизайна (открытости\закрытости и пр.) не учитывались при написании кода.
                                  –6
                                  Прошу прощения, но generic'и в Java ужасны чуть менее, чем полностью. Чрезмерное их использование может превратить проект в ад. Так что в этом плане я согласен с автором. Ну и «редкостная чушь» — это вы перегнули. В статье есть много полезных советов (хоть и не все советы полезны). Учитесь читать не по диагонали.
                                    +1
                                    О! Несомненно! Поругать джава generics есть дело чести любого квалифицированного специалиста, ознакомившегося с этим языком (тэскэть, визитная карточка настоящего профи!), но, справедливости ради, должен заметить, что джава generics не только вредны, но и полезны.

                                    Их просто не нужно путать с C++ templates. В templates, компилятор создаёт экземпляр для каждого употребления шаблона в коде и информация о типе доступна на рантайме. В джава generics, информация на рантайме уже не доступна.

                                    Посему, не комплексуя по поводу того, что generics слабее чем templates, разумно использовать generics во многих местах, давая информацию о типах компилятору, дабы он смог дополнительно проверить типобезопасность. Ничего плохого в этом нет и пользоваться этим полезно.
                                      0
                                      Так и автор статьи не спорит об этом. В чем не прав автор, говоря о том, что дженерики можно периодически использовать?
                                        0
                                        Я же на ваш пост отвечал, а не прямо к статье. Тем самым согласившишь тут с автором.
                                  0
                                  Перенёс выше.
                                    +1
                                    Прочитал статью. Безумно рад, что в свое время ушел из разработчиков «типичных серверных бизнес-приложений». Их жизнь — скука, которая убивает. Имхо.
                                      0
                                      Интересная разкладка. Судя по ней, суждено мне быть разработчиком фреймворков =).
                                      А вообще — не согласен, что NIO переместили в периодичное. В плане работы с сетью (да и сфайлами, в случае масового одновременного записи/чтения и прочего highload) — это очень приятная штука. Понятно, что для одного файла/соединения нет смысла использовать NIO, но в случаях, когда оно правда нужно — очень облегчает работу.
                                        +1
                                        Хотя может автор исходил из соображений, что не каждый день людям нужно писать приложения, рассчитаные на активный файловый-сетевой IO, тогда согласен.
                                          0
                                          Зачем использовать NIO, если есть Netty/Grizzly?
                                            –1
                                            Например, из чистого интереса к тому, как и что происходит немного глубже фреймворка. Вообще у меня наверное предрасположеность к написанию велосипедов — большинство фреймворков/библиотек мне кажутся слишком громадными и перегружеными функционалом, как посмотрю к ним в документацию — всякое желание испльзовать пропадает.
                                          –7
                                          … Но Java давно уже не тот тугодум, что раньше, даже наоборот. И я не могу придумать, какие задачи не могут решить стандартная или сторонние библиотеки…

                                          Ох уж этот религиозный фанатизм… слабая фантазия или просто недостаток опыта?
                                          Вот из реальной жизни таск:
                                          Двухканалтьный АЦП подцепленный по USB выдает отсчеты по простенькому протоколу.
                                          Нужно все считать, проверить целостность и визуализировать данные просто осцилограммой и плюс спектр (fft) в другом окне.
                                          Платформа: Вин ХР Pentium4, 512 метров память. кстати писюк еще не полное борохло — может и хужее быть у зака…

                                          И идет этот очередной юный знаток жабы со своими знаниями в анус, ну или учить что-то нативное — типа си или дельфей — но там тоже надо соображать в особенностях платформы иначе будет все равно тормозить…

                                          Жаба как и НЕТ все тот же тугодум — просто процы стали быстрее :-)
                                            +2
                                            Абсолютно совершенных платформ, закрывающих все типы задач, в жизни не бывает. Можно реализовать вашу задачу на C, но придёт другой умник и веско скажет, что у заказчика то на самом деле калькулятор «Электроника» и писать всё нужно было в его двоичных кодах. А стало быть все остальные языки «сосут» и вообще ерунда и тугодумы…
                                            Ну и так далее.
                                              +2
                                              Какие си, какие дельфи? Вы разве не знаете, что всё, ВСЁ надо переписать на ассемблере?!
                                                +1
                                                А если операционная система не Windows, а другая, поддерживающая USB 3.0 (к примеру FreeBSD или GNU/Linux), то нужно по-любому менять программиста.
                                                0
                                                А я думал у меня одного clone-офобия.
                                                  0
                                                  Композиция очень хорошая штука, но в Java нет автоматического delegate. В итоге приходится для каждого метода вручную писать вызов к delegate.

                                                  По возможности использовать только immutable объекты. Особенно там, где дело касается POJO. Помнить, что для сложных структур данных Java Beans — худшее, что можно только придумать, поскольку не делают различия между ссылкой и значением. Геттеры, возвращающие коллекции, должны либо врапить их в unmodifiable() либо создавать копию коллекции.

                                                  Использовать преимущественно static factory methods, а не конструкторы для создания новых экземпляров.

                                                  Клонирование имеет смысл, когда оно глубокое (весь граф). Его проще сделать через сериализацию-десериализацию.
                                                    0
                                                    Использовать преимущественно static factory methods, а не конструкторы для создания новых экземпляров
                                                    Почему:
                                                      0
                                                      1. Позволяет прозрачно добавить пулинг объектов или кеш в любой момент, или сконвертировать в singleton.
                                                      2. При комбинации более понятные названия методов лучше, чем перегрузка в разных конструкторах. Например, такие:
                                                      Color.newRGB(...)
                                                      Color.newHSL(...)
                                                      Color.fromString( String name )
                                                      Color.fromCSS( String style )
                                                      3. Позволяет подменить возвращаемый объект его специфической имплементацией.
                                                      4. Позволяет не писать дважды generics-параметры при инициализации:
                                                      Pair<String,Integer> pair = new Pair<String,Integer>( «test», 1 )
                                                      Pair<String,Integer> pair = Pair.create( «test», 1 )
                                                      где factory method:
                                                      public static <T1,T2> Pair<T1,T2> create( T1 v1, T2 v2 );
                                                      5. Многие фреймворки требуют дефолтный no-args конструктор для java beans. Если Вы создали свой конструктор с параметрами, также требуется добавить дефолтный no-args. Если же у вас factory methods, то дефолтный конструктор присутствует всегда.
                                                        0
                                                        Ну а если у вас не один из этих кейсов, то вы все равно юзаете статические методы, а не конструкторы? По инерции?
                                                          0
                                                          Нет ессно.
                                                            0
                                                            Ну вот, то есть их не надо «использовать приемущественно», их надо использовать в (вписать).
                                                      0
                                                      На практике использование immutable, увы, остается теорией…
                                                      А еще в контексте этой статьи, наверное стоит упомянуть имя книги, где одно оглавление напоминает Ваши перечисленные пункты — это Effective Java написанная Joshua Bloch, который в свое время реализовал большинство коллекций в JDK. На мой взгляд — Must Read.
                                                      0
                                                      Я подозреваю, что то, про что здесь написано «мне остаётся только молиться за вас» и «это дорога в ад», для практики программирования на С++ — в общем, рядовые вещи…
                                                        0
                                                        лучше оставить работу с ним на откуп фреймворкам и библиотекам
                                                        Про прокси, рефлексию и классозагрузчики. Надо понимать, чем опасно написание собственных фреймворков. Надо понимать, разницу между, условно говоря, «админским» программированием, когда нужно автоматизировать решение задачи, которую, в принципе, можно решать и вручную, только в 1000 раз дольше, и временнЫе рамки не жёсткие, и «трудовым» программированием в команде, когда стоит задача по максимуму полезно использовать оплачиваемое время программистов. Что такое риски и надёжность и какова их роль, что такое тестирование и насколько важно сохранение работоспособности программы при её изменениях и почему эти изменения неизбежны. Ну и про IDE со встроенным рефакторингом, что делает изменение программ более простым делом. Тогда сразу возникает понимание, что использование рефлексии сильно повышает вероятность неотлавливаемых компилятором ошибок, особенно возникновение их при переименовании членов класса. И что прокси, рефлексию и классозагрузчики нужно тестировать особенно тщательно, поэтому их используют в малом количестве, сосредотачивают в одном месте, и желательно, чтоб за работоспособность этого места нёс ответственность не ты, что разработка фреймворков требует фактически другой организации бизнес-процесса.

                                                        Only users with full accounts can post comments. Log in, please.