<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DUINRnY_eCp7ImA9WhRaE0Q.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198</id><updated>2012-02-16T17:06:37.840+04:00</updated><category term="математика" /><category term="забавно" /><category term="ооп" /><category term="задротство" /><category term="java" /><category term="игры" /><category term="gnu/linux" /><category term="книга" /><category term="canon" /><category term="scjp" /><category term="приключения" /><category term="многопоточность" /><category term="рекомендую" /><category term="принтер" /><category term="android" /><category term="извращение" /><category term="eclim" /><category term="windows" /><category term="effective java" /><category term="перевод" /><category term="мнение" /><category term="eclipse" /><category term="ubuntu" /><category term="боль" /><category term="отзыв" /><category term="general programming" /><category term="безопасность" /><title>Coding Break</title><subtitle type="html">Иногда мне кажется, что компилятор игнорирует мои комментарии.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://codingbreak.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>38</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/CodingBreak" /><feedburner:info uri="codingbreak" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0UCQXczfSp7ImA9WhZaFkU.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-970525118411575532</id><published>2011-07-03T14:34:00.000+04:00</published><updated>2011-07-03T14:34:20.985+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-03T14:34:20.985+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="eclim" /><category scheme="http://www.blogger.com/atom/ns#" term="извращение" /><category scheme="http://www.blogger.com/atom/ns#" term="eclipse" /><category scheme="http://www.blogger.com/atom/ns#" term="мнение" /><title>Eclim: установка и впечатления</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;&lt;a href="http://eclim.org/"&gt;Eclim&lt;/a&gt; - программа, которая призвана внести возможности Eclipse в Vim, чтобы облегчить разработку программ на Java, C/C++, Ruby, PHP, Python в последнем.&lt;/p&gt;&lt;br /&gt;
&lt;big&gt;&lt;b&gt;Установка&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;p&gt;По установке Eclim-а есть официальная &lt;a href="http://eclim.org/guides/install.html"&gt;инструкция&lt;/a&gt;. Я устанавливал на Ubuntu, хотелось бы сделать несколько замечаний по этому поводу.&lt;/p&gt;&lt;p&gt;Требования: JDK 1.5+, Vim 7.1.x, Eclipse 3.7.x Indigo. Считаем, что JDK у нас есть. Vim 7.3, который можно установить из репозитория Ubuntu, подходит. Eclipse в репозитории старый, поэтому нужную версию придётся &lt;a href="http://eclipse.org/downloads/index.php"&gt;скачать&lt;/a&gt;. Будем считать, что Eclipse у нас в &lt;code&gt;/home/user/eclipse/&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Установщик только графический. Он довольно неудобен.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-03gMa2p8C_I/Tg8axstvmUI/AAAAAAAAAfE/clPwMiiI5yU/s1600/Screenshot-Eclim+Installer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://1.bp.blogspot.com/-03gMa2p8C_I/Tg8axstvmUI/AAAAAAAAAfE/clPwMiiI5yU/s320/Screenshot-Eclim+Installer.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;В нашем случае Eclipse Home и User Local Eclipse пути должны быть &lt;code&gt;/home/user/eclipse/&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Установщик скачает нужные пакеты и Eclim установится.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;big&gt;&lt;b&gt;Запуск и работа&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;p&gt;Eclim предлагает несколько способов применения. Можно разрабатывать в Vim без запуска Eclipse, можно запустить Eclipse и использовать Vim в качестве редактора исходников, а можно совмещать. Принципиальной разницы в настройке Eclim здесь нет. Существуют также и другие средства, которые позволяют использовать Vim внутри Eclipse, например, &lt;a href="http://sourceforge.net/projects/vimplugin/"&gt;Vimplugin&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Нужно запустить демон eclimd, он находится в папке &lt;code&gt;/home/user/eclipse/&lt;/code&gt;. Ждём сообщения &lt;code&gt;Eclim Server Started on: 127.0.0.1:9091&lt;/code&gt; в его выводе прежде, чем продолжить.&lt;/p&gt;&lt;p&gt;Далее открываем и выполняем &lt;a href="http://eclim.org/gettingstarted.html"&gt;Getting Started&lt;/a&gt;. У меня &lt;code&gt;.classpath&lt;/code&gt; нового Java проекта сам наполнился нужными данными, добавлять ничего не пришлось. Команды &lt;code&gt;:NewSrcEntry&lt;/code&gt; в Vim-е не обнаружилось.&lt;/p&gt;&lt;p&gt;Следуем инструкции до пункта 4, где нам предлагается испытать автозавершение (autocompletion). Автозавершение по &lt;code&gt;ctrl+n&lt;/code&gt; у меня выдаёт какие-то общие ключевые слова, которые не подходят к контексту. &lt;code&gt;Ctrl+x + ctrl+u&lt;/code&gt; не заработало (&amp;laquo;Option 'completefunc' is not set&amp;raquo;). Чтобы починить, нужно в файл &lt;code&gt;.vimrc&lt;/code&gt; добавить строку &lt;code&gt;filetype plugin indent on&lt;/code&gt;, об этом написано в &lt;a href="http://eclim.org/guides/troubleshoot.html?highlight=troubleshooting"&gt;Eclim Troubleshooting&lt;/a&gt;. Если файла &lt;code&gt;.vimrc&lt;/code&gt; нет в домашней папке, надо создать.&lt;/p&gt;&lt;p&gt;Так выглядит автозавершение:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-IohTGYmbUlw/Tg8o4FbEBhI/AAAAAAAAAfI/HLMAXtjS8Jg/s1600/Screenshot-Terminal.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="210" src="http://2.bp.blogspot.com/-IohTGYmbUlw/Tg8o4FbEBhI/AAAAAAAAAfI/HLMAXtjS8Jg/s320/Screenshot-Terminal.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;Компиляция и запуск программы выполняются командами &lt;code&gt;:Javac&lt;/code&gt; и &lt;code&gt;:Java&lt;/code&gt;. Ворнинги отображаются только в редакторе, при компиляции их не видно.&lt;/p&gt;&lt;big&gt;&lt;b&gt;Впечатления&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;p&gt;Для себя я сделал вывод, что в качестве среды разработки Vim не катит. Это хороший редактор, но разрабатывать в нём быстрее, чем в Eclipse, не получится.&lt;/p&gt;&lt;p&gt;Однако тем, кто считает Vim лучшим редактором &lt;i&gt;для всего&lt;/i&gt;, Eclim может пригодиться как частичная замена Eclipse. Напомню, что совсем избавиться от Eclipse в системе не получится - Eclim его использует.&lt;/p&gt;&lt;p&gt;Если кто вдруг не знает, в эклипсе есть до фига сочетаний клавиш. Открытие файлов, переключение между вкладками, quick outline, автодополнение, форматирование, компиляция, запуск - все эти и другие действия в Eclipse можно и нужно выполнять без мыши.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-970525118411575532?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/oPDe9IuKyHw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/970525118411575532/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/07/eclim.html#comment-form" title="Комментарии: 5" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/970525118411575532?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/970525118411575532?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/oPDe9IuKyHw/eclim.html" title="Eclim: установка и впечатления" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-03gMa2p8C_I/Tg8axstvmUI/AAAAAAAAAfE/clPwMiiI5yU/s72-c/Screenshot-Eclim+Installer.png" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/07/eclim.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EBSHc8eip7ImA9WhZUEkQ.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-7781025637705876419</id><published>2011-06-05T22:47:00.000+04:00</published><updated>2011-06-05T22:47:39.972+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-05T22:47:39.972+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gnu/linux" /><category scheme="http://www.blogger.com/atom/ns#" term="приключения" /><title>Настраивал vsftpd на CentOS</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;Настроил. Захожу под тестовой учётной записью и вижу: текущая директория (pwd) верная, а файла, который там лежит, не видно. Проверил настройки - всё верно. Проверил права доступа - всё есть. Поискал в интернете - ничего толкового не нашёл.&lt;/p&gt;&lt;p&gt;В итоге проблема решилась отключением SELinux. Эта зараза, как оказалось, может молча отбирать права у процессов, если ей что-то не понравится. Особенно неприятно, когда такие тонкие моменты всплывают на зачёте по системному администрированию.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-7781025637705876419?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/IgaZhkpgmpg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/7781025637705876419/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/06/vsftpd-centos.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7781025637705876419?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7781025637705876419?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/IgaZhkpgmpg/vsftpd-centos.html" title="Настраивал vsftpd на CentOS" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/06/vsftpd-centos.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8MSXg5fCp7ImA9WhZWFk8.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-3935903615884601728</id><published>2011-05-17T14:41:00.000+04:00</published><updated>2011-05-17T14:41:28.624+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-17T14:41:28.624+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gnu/linux" /><category scheme="http://www.blogger.com/atom/ns#" term="canon" /><category scheme="http://www.blogger.com/atom/ns#" term="боль" /><category scheme="http://www.blogger.com/atom/ns#" term="принтер" /><category scheme="http://www.blogger.com/atom/ns#" term="ubuntu" /><title>Про принтеры Canon в Ubuntu</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;По&amp;nbsp;ужасному стечению обстоятельств я&amp;nbsp;являюсь владельцем лазерного принтера Canon LBP2900 и&amp;nbsp;постоянным пользователем Ubuntu (других&amp;nbsp;ОС на&amp;nbsp;домашнем ноутбуке нет). Принтеры этой серии (про другие серии не&amp;nbsp;в&amp;nbsp;курсе)&amp;nbsp;&amp;mdash; большая головная боль для линуксоидов, поскольку протоколы закрыты, а&amp;nbsp;официальные драйвера под линукс ужасны.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;Недавно появилась &lt;a href="http://www.linux.org.ru/news/hardware/6134296"&gt;новость о&amp;nbsp;разработке открытого драйвера принтеров Canon&lt;/a&gt;. Драйвер разрабатывается путём реверс-инжиниринга официального. На&amp;nbsp;днях мне нужно было срочно установить мой принтер в&amp;nbsp;новенькую Ubuntu&amp;nbsp;11.04, но&amp;nbsp;с&amp;nbsp;этим драйвером я&amp;nbsp;не&amp;nbsp;разобрался, к&amp;nbsp;сожалению. Не&amp;nbsp;стал рисковать временем и&amp;nbsp;решил действовать по-старинке, поставить кривые официальные драйвера.&lt;/p&gt;&lt;p&gt;Здесь нужно заметить, что &amp;laquo;правильно&amp;raquo; установить кэноновские драйвера не&amp;nbsp;просто. Существует несколько инструкций, но&amp;nbsp;не&amp;nbsp;все работают. Оказалось, один хороший человек написал скрипт для установки драйвера, который автоматизирует этот процесс почти полностью и&amp;nbsp;экономит много времени. Скрипт работает, в том числе, и в&amp;nbsp;Ubuntu&amp;nbsp;11.04 &amp;laquo;Natty Narwhal&amp;raquo;. &lt;a href="http://radu.cotescu.com/how-to-install-canon-lbp-printers-in-ubuntu/"&gt;Вот он&lt;/a&gt;. Архив содержит и&amp;nbsp;сами драйвера, то&amp;nbsp;есть искать и&amp;nbsp;скачивать их&amp;nbsp;отдельно не&amp;nbsp;нужно.&lt;/p&gt;&lt;p&gt;Стоит добавить, что для успешной установки драйверов могут понадобиться пакеты &lt;a href="http://packages.debian.org/search?keywords=cupsys"&gt;cupsys&lt;/a&gt; и&amp;nbsp;&lt;a href="http://packages.debian.org/search?keywords=gs-esp"&gt;gs-esp&lt;/a&gt;. Иначе в&amp;nbsp;логе скрипта вы&amp;nbsp;увидете сообщения apt-get об&amp;nbsp;ошибках.&lt;/p&gt;&lt;p&gt;Сам официальный драйвер очень глючный. Время от&amp;nbsp;времени принтер просто перестаёт печатать, иногда при этом ещё capt и&amp;nbsp;cupsd полностью загружают процессор. В&amp;nbsp;этих случаях помогает одно из&amp;nbsp;следующих действий:&lt;ul&gt;&lt;li&gt;отменить печать, перезагрузить cupsd: &lt;code&gt;sudo restart cupsd&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;перезагрузить принтер;&lt;/li&gt;
&lt;li&gt;перезагрузить компьютер.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-3935903615884601728?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/6WAuksYorpw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/3935903615884601728/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/05/canon-ubuntu.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/3935903615884601728?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/3935903615884601728?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/6WAuksYorpw/canon-ubuntu.html" title="Про принтеры Canon в Ubuntu" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/05/canon-ubuntu.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8DRHg4eyp7ImA9WhZWEE4.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-2914708911130677283</id><published>2011-05-10T18:31:00.000+04:00</published><updated>2011-05-10T18:31:15.633+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-10T18:31:15.633+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="eclipse" /><title>Не работает автодополнение в Eclipse</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;Иногда случается, что какой-то воркспейс использовался с&amp;nbsp;одной версией Eclipse, потом стал использоваться с&amp;nbsp;другой версией Eclipse и&amp;nbsp;тут сломалось автодополнение (autocompletion) в Java. Решение в&amp;nbsp;таком случае очень простое&amp;nbsp;&amp;mdash; надо создать новый воркспейс и&amp;nbsp;импортировать туда проекты из&amp;nbsp;старого, при этом отметив &amp;laquo;Copy projects into workspace&amp;raquo;.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-2914708911130677283?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/S3GcJE1GsZs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/2914708911130677283/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/05/eclipse.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2914708911130677283?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2914708911130677283?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/S3GcJE1GsZs/eclipse.html" title="Не работает автодополнение в Eclipse" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/05/eclipse.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4HQHY5fyp7ImA9WhZWEE4.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-2247218244775123285</id><published>2011-05-10T18:29:00.001+04:00</published><updated>2011-05-10T18:32:11.827+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-10T18:32:11.827+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="многопоточность" /><title>Effective Java: Concurrency</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;Напоминаю, что данная серия постов&amp;nbsp;&amp;mdash; кратчайшее изложение основных мыслей книги &lt;a href="http://java.sun.com/docs/books/effective/"&gt;Effective Java 2nd edition&lt;/a&gt;. Они не&amp;nbsp;заменят книги, но&amp;nbsp;помогут освежить кое-что в&amp;nbsp;памяти.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;66. Синхронизируйте доступ к&amp;nbsp;общим (shared) изменяемым (mutable) данным.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Параграф о&amp;nbsp;применении ключевых слов &lt;code&gt;synchronized&lt;/code&gt; и &lt;code&gt;volatile&lt;/code&gt;. Автор делает следующие выводы: лучше всего избегать межпоточной синхронизации использованием immutable объектов. Если это невозможно, всегда нужна синхронизация, иначе результат работы программы будет непредсказуем. В&amp;nbsp;случаях, когда блокировки (ключевое слово &lt;code&gt;synchronized&lt;/code&gt;) не&amp;nbsp;нужны, допустимо использовать &lt;code&gt;volatile&lt;/code&gt;. Но&amp;nbsp;и&amp;nbsp;с&amp;nbsp;ним не&amp;nbsp;всё так просто&amp;nbsp;&amp;mdash; надо помнить, что не&amp;nbsp;все операции атомарны (&lt;code&gt;++&lt;/code&gt; и &lt;code&gt;--&lt;/code&gt; не&amp;nbsp;атомарны, операции чтения и&amp;nbsp;записи для &lt;code&gt;long&lt;/code&gt; и &lt;code&gt;double&lt;/code&gt; тоже).&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;67. Избегайте избыточной синхронизации.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Никогда не&amp;nbsp;запускайте &amp;laquo;чужой&amp;raquo; (alien) код внутри синхронизированных блоков. &amp;laquo;Чужим&amp;raquo; называется код, предоставляемый клиентом вашего API. Соответственно, вы&amp;nbsp;не&amp;nbsp;знаете, что и&amp;nbsp;как будет выполняться в&amp;nbsp;этом коде, поэтому в&amp;nbsp;некоторых случаях выполнение &amp;laquo;чужого&amp;raquo; кода может привести к&amp;nbsp;дедлокам (deadlocks), состоянию гонки (race condition) ошибкам выполнения. Автор приводит пример кода с&amp;nbsp;такой проблемой. Выполнение &amp;laquo;чужого&amp;raquo; кода нужно выносить за&amp;nbsp;пределы &lt;code&gt;synchronized&lt;/code&gt;-блоков. Если это невозможно, синхронизацию следует переложить на&amp;nbsp;клиентский код, при этом явно задокументировав потоковую небезопасность вашего API.&lt;/p&gt;&lt;p&gt;Вообще, синхронизация дорога во&amp;nbsp;многих отношениях, поэтому внутри синхронизованных блоков нужно выполнять как можно меньше действий, по&amp;nbsp;возможности вынося все долгие операции наружу.&lt;/p&gt;&lt;p&gt;Если ваш класс не&amp;nbsp;предполагает обязательной многопоточности, лучше вообще ничего не&amp;nbsp;синхронизовывать&amp;nbsp;&amp;mdash; пусть лучше клиент об&amp;nbsp;этом заботится. Это правило нарушено во&amp;nbsp;многих старых стандартных классах, например, в &lt;code&gt;StringBuffer&lt;/code&gt;. Он&amp;nbsp;синхронизован внутри, хотя чаще всего использовался в&amp;nbsp;одном потоке. Поэтому пришлось создавать его несихронизованный аналог &lt;code&gt;StringBuilder&lt;/code&gt;, которым мы&amp;nbsp;почти всегда и&amp;nbsp;пользуемся.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;68. Предпочитайте executors и&amp;nbsp;tasks вместо &amp;laquo;сырых&amp;raquo; потоков.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;В&amp;nbsp;Java&amp;nbsp;1.5 появился пакет &lt;code&gt;java.util.concurrent&lt;/code&gt;, содержащий Executor Framework. Данный фреймворк предоставляет классы, упрощающие выполнение очередей задач в&amp;nbsp;однопоточном, многопоточном режимах или по&amp;nbsp;таймеру. Благодаря им&amp;nbsp;больше не&amp;nbsp;нужно писать свои собственные безопасные очереди и&amp;nbsp;диспетчеры потоков.&lt;/p&gt;&lt;p&gt;Кроме того, фреймворк вводит понятие задач (tasks), представленных двумя интерфейсами &lt;code&gt;Runnable&lt;/code&gt; и &lt;code&gt;Callable&lt;/code&gt;. Эти интерфейсы позволяют абстрагироваться от&amp;nbsp;потоков и&amp;nbsp;не&amp;nbsp;работать с&amp;nbsp;ними напрямую.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;69. Предпочитайте готовые многопоточные утилиты вместо &lt;code&gt;wait&lt;/code&gt; и &lt;code&gt;notify&lt;/code&gt;.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Пакет &lt;code&gt;java.util.concurrent&lt;/code&gt; кроме Executor Framework содержит ещё и&amp;nbsp;потокобезопасные коллекции и&amp;nbsp;синхронизаторы (synchronizers). Данный параграф рассказывает о&amp;nbsp;двух последних.&lt;/p&gt;&lt;p&gt;Потокобезопасные коллекции&amp;nbsp;&amp;mdash; высокоэффективные имплементации стандартных интерфейсов &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Queue&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;. Они синхронизованны внутри. Некоторые из&amp;nbsp;них имеют особые методы типа &lt;code&gt;map.putIfAbsent(key, value)&lt;/code&gt; для обеспечения атомарности подобных операций. Эти коллекции рекомендуется использовать вместо устаревших &lt;code&gt;Collections.synchronized&lt;i&gt;XXX&lt;/i&gt;&lt;/code&gt;, поскольку первые более производительны.&lt;/p&gt;&lt;p&gt;Синхронизаторы&amp;nbsp;&amp;mdash; объекты, заставляющие потоки ждать друг друга, прежде, чем начать выполнение. Наиболее часто используемые: &lt;code&gt;CountDownLatch&lt;/code&gt;, &lt;code&gt;Semaphore&lt;/code&gt;. Наименее используемые: &lt;code&gt;CyclicBarrier&lt;/code&gt;, &lt;code&gt;Exchanger&lt;/code&gt;. Про них по-хорошему нужно читать в&amp;nbsp;специализированных статьях и&amp;nbsp;книгах.&lt;/p&gt;&lt;p&gt;Причин использовать &lt;code&gt;wait&lt;/code&gt; и &lt;code&gt;notify&lt;/code&gt; в&amp;nbsp;новом коде крайне мало. Если приходится поддерживать старый код, использующий эти методы, нужно помнить, что &lt;code&gt;wait()&lt;/code&gt; всегда должен располагаться в&amp;nbsp;цикле while с&amp;nbsp;проверкой условия пробуждения.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;70. Документируйте потокобезопасность.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;При настройках по&amp;nbsp;умолчанию Javadoc не&amp;nbsp;включает ключевые слова &lt;code&gt;synchronized&lt;/code&gt; в&amp;nbsp;документацию, и&amp;nbsp;правильно делает. Потокобезопасность нужно документировать самостоятельно. Существует 5&amp;nbsp;уровней потокобезопасности:&lt;ul&gt;&lt;li&gt;Неизменяемые (immutable) классы&amp;nbsp;&amp;mdash; синхронизация не&amp;nbsp;нужна. Примеры&amp;nbsp;&amp;mdash; &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Long&lt;/code&gt;, &lt;code&gt;BigInteger&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Безусловно потокобезопасные классы&amp;nbsp;&amp;mdash; экземпляры класса изменяемы, но&amp;nbsp;синхронизованны внутри, и&amp;nbsp;внешняя синхронизация не&amp;nbsp;требуется. Примеры&amp;nbsp;&amp;mdash; &lt;code&gt;Random&lt;/code&gt;, &lt;code&gt;ConcurrentHashMap&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Условно потокобезопасные классы&amp;nbsp;&amp;mdash; некоторые методы требуют внешней синхронизации. Например, врапперы &lt;code&gt;Collections.synchronized&lt;i&gt;XXX&lt;/i&gt;&lt;/code&gt; - их&amp;nbsp;итераторы требуют дополнительной синхронизации.&lt;/li&gt;
&lt;li&gt;Не&amp;nbsp;потокобезопасные классы&amp;nbsp;&amp;mdash; их&amp;nbsp;экземпляры изменяемы, нужна внешняя синхронизация. Пример&amp;nbsp;&amp;mdash; коллекции из &lt;code&gt;java.util&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Враждебные многопоточности (thread-hostile) классы, методы&amp;nbsp;&amp;mdash; им&amp;nbsp;не&amp;nbsp;помогает даже внешная синхронизация. В&amp;nbsp;основном, это происходит, когда экземпляры работают со&amp;nbsp;статическими данными класса. Такие классы&amp;nbsp;&amp;mdash; редкость, они появляются, если кто-то не&amp;nbsp;расчитывает на&amp;nbsp;многопоточность при проектировании.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;71. Используйте ленивую инициализацию с&amp;nbsp;умом.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Параграф описывает способы осуществления ленивой инициализации. Если не&amp;nbsp;позаботиться о&amp;nbsp;многопоточности, может случаться повторная инициализация.&lt;/p&gt;&lt;p&gt;Когда нужно лениво инциализировать статическое поле, используйте holder class idiom; когда не&amp;nbsp;статическое поле&amp;nbsp;&amp;mdash; double-check idiom. И&amp;nbsp;помните, что оптимизировать нужно только тогда, когда это действительно необходимо.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;72. Не&amp;nbsp;полагайтесь на&amp;nbsp;планировщик потоков.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Код, полагающийся в&amp;nbsp;своей корректности или производительности на&amp;nbsp;алгоритм планировщика потоков, не&amp;nbsp;переносим. Количество работающих (runnable) потоков не&amp;nbsp;должно значительно превышать количество процессоров. Потоки не&amp;nbsp;должны работать, если они не&amp;nbsp;делают никакой полезной работы. Нужно избегать использования &lt;code&gt;Thread.yield()&lt;/code&gt; - если производительность низкая, лучше реорганизовать рабочие потоки. Приоритеты потоков допустимо использовать, чтобы немного подрегулировать перфоманс, однако на&amp;nbsp;них нельзя полагаться при решении более серьёзных проблем с&amp;nbsp;многопоточностью. Они тоже реализованы по-разному в&amp;nbsp;разных JVM, некоторые виртуальные машины могут попросту их&amp;nbsp;игнорировать.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item&amp;nbsp;73. Избегайте использования групп потоков (thread groups).&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Группы потоков были придуманы с&amp;nbsp;целью изолировать java-апплеты для безопасности, но&amp;nbsp;они так и&amp;nbsp;не&amp;nbsp;справились с&amp;nbsp;этим. Сейчас этот API совершенно устарел. Нет причин использовать его в&amp;nbsp;коде.&lt;/p&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-2247218244775123285?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/-KzVRSuxwM4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/2247218244775123285/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/05/effective-java-concurrency.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2247218244775123285?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2247218244775123285?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/-KzVRSuxwM4/effective-java-concurrency.html" title="Effective Java: Concurrency" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/05/effective-java-concurrency.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UNQn07fip7ImA9WhdTGUQ.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-8064906122997084378</id><published>2011-04-02T20:01:00.002+04:00</published><updated>2011-07-18T18:28:13.306+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-18T18:28:13.306+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="книга" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="мнение" /><category scheme="http://www.blogger.com/atom/ns#" term="задротство" /><category scheme="http://www.blogger.com/atom/ns#" term="отзыв" /><category scheme="http://www.blogger.com/atom/ns#" term="scjp" /><title>Отзыв о книге «A Programmer's Guide to Java SCJP Certification: A Comprehensive Primer (3rd Edition)»</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: right;"&gt;&lt;a href="http://goo.gl/8kyli" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-3nqNufhhEos/TZc4k5U3j6I/AAAAAAAAAeU/WsPouFE4XEA/s1600/scjp_book.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;Авторы: Khalid Mughal, Rolf Rasmussen.&lt;/p&gt;&lt;p&gt;Данная книга представляет собой руководство по подготовке к сертификационному экзамену SCJP. Книга здоровая - около 1000 страниц. Впечатления после её прочтения немного противоречивые. С одной стороны, она полностью и подробно покрывает все темы, которые нужно знать. С другой стороны, есть и другие книги по подготовке к экзамену SCJP, гораздо менее толстые. Я думаю, что можно было прочитать одну из таких книг, а в сэкономленное время порешать побольше практических тестов.&lt;/p&gt;&lt;p&gt;После каждой главы есть небольшие тесты по теме - можно воспользоваться ими для проверки и закрепления знаний, даже если читали другую книгу.&lt;/p&gt;&lt;p&gt;В конце книги есть тест для самопроверки, покрывающий своими 72 вопросами множество тем, как реальный экзамен. Но имеет место одна странность. Каждый вопрос имеет своё количество правильных ответов, это число указано в условии. Есть список правильных ответов с объяснением. Но для некоторых вопросов число правильных ответов не совпадает с числом, указанным в вопросе! Я этого совершенно не понял.&lt;/p&gt;&lt;p&gt;В общем, если меня кто-то спросит, что почитать по Java, я, скорее всего, порекомендую какое-нибудь более скромное руководство и второе издание &amp;laquo;Effective Java&amp;raquo;. Читать же эту книгу оказалось совершенным задротством.&lt;/p&gt;&lt;p&gt;Конечно, это только моё личное мнение, поэтому не рекомендую делать выбор, основываясь только на нём.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-8064906122997084378?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/DHHxlhDR1EA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/8064906122997084378/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/04/programmers-guide-to-java-scjp.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/8064906122997084378?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/8064906122997084378?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/DHHxlhDR1EA/programmers-guide-to-java-scjp.html" title="Отзыв о книге &amp;laquo;A Programmer's Guide to Java SCJP Certification: A Comprehensive Primer (3rd Edition)&amp;raquo;" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-3nqNufhhEos/TZc4k5U3j6I/AAAAAAAAAeU/WsPouFE4XEA/s72-c/scjp_book.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/04/programmers-guide-to-java-scjp.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04ESX87eCp7ImA9WhZSF0g.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-6498004365902175477</id><published>2011-04-02T19:58:00.000+04:00</published><updated>2011-04-02T19:58:28.100+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-02T19:58:28.100+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Exceptions</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;Продолжаем. Сегодня речь о 9-й главе &amp;laquo;Exceptions&amp;raquo;.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 57. Используйте exception-ы только для исключительных (exceptional) ситуаций.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Автор приводит пример применения исключений не по назначению для итерации по массиву без проверки выходна за границу.&lt;/p&gt;&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#696969; '&gt;// Horrible abuse of exceptions. Don't ever do this!&lt;/span&gt;
try &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    &lt;span style='color:#bb7977; '&gt;int&lt;/span&gt; i &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#008c00; '&gt;0&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;while&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;true&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;
        range&lt;span style='color:#808030; '&gt;[&lt;/span&gt;i&lt;span style='color:#808030; '&gt;+&lt;/span&gt;&lt;span style='color:#808030; '&gt;+&lt;/span&gt;&lt;span style='color:#808030; '&gt;]&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;climb&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt; catch(ArrayIndexOutOfBoundsException e) &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;Такой подход может ошибочно применятся для ускорения программы, однако имеет большое число недостатков. В их числе - плохое влияние на действительную производительность.&lt;/p&gt;&lt;p&gt;Мораль такова: exception-ы не случайно названы именно так и должны использоваться только для обработки исключительных ситуаций, а не для контроля за нормальным выполнением программы.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 58. Используйте проверяемые исключения (checked exceptions) в поправимых ситуациях и непроверяемые исключения (runtime exceptions) при программных ошибках.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Основная идея заложена в названии. Правда, зачастую невозможно точно определить, к какому типу исключения относится та или иная ситуация - в этом случае нужно выбирать наиболее подходящий вариант. Кроме того, полезно помнить:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Принято считать, что класс &lt;code&gt;Error&lt;/code&gt; и его подклассы используются только виртуальной машиной, и наследоваться от них не надо - вместо этого использовать &lt;code&gt;RuntimeException&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Не имеет смысла напрямую имплементировать &lt;code&gt;Throwable&lt;/code&gt;, не наследуясь от какого-либо &lt;code&gt;Exception&lt;/code&gt;-а. Поведение будет такое же, как и у checked exceptions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Exception&lt;/code&gt;-ы - полноценные объекты, для которых можно и нужно объявлять дополнительные методы, предоставляющие информацию об исключении.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 59. Избегайте лишних проверяемых исключений (checked exceptions).&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Злоупотребление проверяемыми исключениями приводит к неудобствам при использовании вашего API. Если исключение можно предотвратить проверкой специальных условий (как метод &lt;code&gt;hasNext()&lt;/code&gt; класса &lt;code&gt;Iterator&lt;/code&gt;), либо клиент не сможет предпринять никаких полезных действий при возникновении исключения, то использование runtime exception - наилучший выбор.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 60. Предпочитайте стандартные классы-исключения.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Применение стандартных исключений полезно хотя бы потому, что все их знают, и использование вашего API будет таким образом упрощено. Самые часто применяемые исключения из стандартной библиотеки: &lt;code&gt;IllegalArgumentException&lt;/code&gt;, &lt;code&gt;IllegalStateException&lt;/code&gt;, &lt;code&gt;NullPointerException&lt;/code&gt;, &lt;code&gt;IndexOutOfBoundsException&lt;/code&gt;, &lt;code&gt;ConcurrentModificationException&lt;/code&gt;, &lt;code&gt;UnsupportedOperationException&lt;/code&gt;. Важно не забывать, что exception должен соответствовать исключительной ситуации не только по названию, но и по семантике, описанной в документации к исключению. Также бывает полезно наследоваться от стандартных исключений для добавления в них какой-либо полезной информации.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 61. Кидайте исключения, соответствующие уровню абстракции.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Классы высокого уровня должны перехватывать низкоуровневые исключения и заменять их более подходящими для текущей абстракции:&lt;/p&gt;&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#3f5fbf; '&gt;/**&lt;/span&gt;
&lt;span style='color:#3f5fbf; '&gt;&amp;#xa0;&lt;/span&gt;&lt;span style='color:#7f9fbf; font-weight:bold; '&gt;*&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt; Returns the element at the specified position in this list.&lt;/span&gt;
&lt;span style='color:#3f5fbf; '&gt;&amp;#xa0;&lt;/span&gt;&lt;span style='color:#7f9fbf; font-weight:bold; '&gt;*&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt; &lt;/span&gt;&lt;span style='color:#7f9fbf; font-weight:bold; '&gt;@throws&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt; IndexOutOfBoundsException if the index is out of range&lt;/span&gt;
&lt;span style='color:#3f5fbf; '&gt;&amp;#xa0;&lt;/span&gt;&lt;span style='color:#7f9fbf; font-weight:bold; '&gt;*&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt; ({&lt;/span&gt;&lt;span style='color:#7f9fbf; font-weight:bold; '&gt;@&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt;code index &amp;lt; &lt;/span&gt;&lt;span style='color:#008c00; '&gt;0&lt;/span&gt;&lt;span style='color:#3f5fbf; '&gt; || index &gt;= size()}).&lt;/span&gt;
&lt;span style='color:#3f5fbf; '&gt;&amp;#xa0;*/&lt;/span&gt;
&lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; E get(int index) &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    ListIterator&lt;span style='color:#808030; '&gt;&amp;lt;&lt;/span&gt;E&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; i &lt;span style='color:#808030; '&gt;=&lt;/span&gt; listIterator&lt;span style='color:#808030; '&gt;(&lt;/span&gt;index&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;try&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; i&lt;span style='color:#808030; '&gt;.&lt;/span&gt;next&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;catch&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#bb7977; font-weight:bold; '&gt;NoSuchElementException&lt;/span&gt; e&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;throw&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; &lt;span style='color:#bb7977; font-weight:bold; '&gt;IndexOutOfBoundsException&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#0000e6; '&gt;"Index: "&lt;/span&gt; &lt;span style='color:#808030; '&gt;+&lt;/span&gt; index&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;Это называется exception translation idiom. Особая её форма - exception chaining - когда низкоуровневое исключение не отбрасывается, а сохраняется в поле cause высокоуровнего исключения:&lt;/p&gt;&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#696969; '&gt;// Exception Chaining&lt;/span&gt;
try &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    &lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt; &lt;span style='color:#696969; '&gt;// Use lower-level abstraction to do our bidding&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt; catch (LowerLevelException cause) &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;throw&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; HigherLevelException&lt;span style='color:#808030; '&gt;(&lt;/span&gt;cause&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;В этом случае стек трейсы исключений будут выводиться в сцепленном виде. Это является, в некотором роде, нарушением инкапсуляции, поэтому злоупотреблять не стоит.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 62. Документируйте кидаемые исключения.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Под документированием исключений понимается их пораздельное объявление с точным описанием условий возникновения.&lt;/p&gt;&lt;p&gt;Описывайте каждое проверяемое исключение (checked exception), которое может быть кинуто из ваших методов, используйте для этого javadoc-тег &lt;code&gt;@throws&lt;/code&gt;. Непроверяемые исключения тоже важно упоминать в документации, но не с тегом &lt;code&gt;@throws&lt;/code&gt;, а просто в описании метода. Конечно, описать всевозможные runtime exceptions далеко не всегда представляется возможным. Всё это относится как к конкретным методам, так и к абстрактным и методам в интерфейсах.&lt;/p&gt;&lt;p&gt;Если одно и то же исключение кидается многими методами одного класса или интерфейса при одинаковых условиях, допустимо описать его в документации самого класса или интерфейса.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 63. Включайте в исключения информацию об ошибках.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Когда программа падает с непроверяемым исключением, stack trace и текстовое сообщение из исключения попадают в лог или консоль. Если ошибку трудно или невозможно воспроизвести, то эта вся информация, доступная разработчикам для поиска ошибки. Поэтому важно наделять текст исключения всеми важными значениями, касающимися исключительной ситуации. Проверяемые исключения полезно обеспечивать методами-аксессорами к этим значениям, которые могут пригодиться при обработке исключения в &lt;code&gt;catch&lt;/code&gt;-блоке.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 64. Стремитесь к атомарности сбоев (failure atomicity).&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Любое задокументированное исключение, сгенерированное методом объекта, должно оставлять объект в рабочем состоянии - это и называется failure atomicity. Если добиться такого эффекта слишком сложно или невозможно, нужно ясно заявить об этом в документации.&lt;/p&gt;&lt;p&gt;Для неизменяемых (immutable) инстансов failure atomicity гарантирована по определению. Добиться её в остальных случаях можно одним из следующих способов (по убыванию популярности):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;проверять входные параметры каждого метода до выполнения каких-либо действий;&lt;/li&gt;
&lt;li&gt;выполнять все &amp;laquo;опасные&amp;raquo; вычисления до изменения состояния объекта;&lt;/li&gt;
&lt;li&gt;писать восстанавливающий код для отката объекта в консистентное состояние;&lt;/li&gt;
&lt;li&gt;выполнять действия над временной копией объекта. Пример - метод &lt;code&gt;Collections.sort()&lt;/code&gt; копирует объекты из коллекции во временный массив (в т. ч. для лучшей скорости), сортирует их, затем копирует обратно.&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;&lt;b&gt;Item 65. Не игнорируйте исключения.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Кажется, это очевидно. Исключения придуманы для того, чтобы заставить программиста учитывать их и выполнять какие-либо действия при их возникновении, а не игнорировать их. В самом крайнем случае, когда никакие действия и правда не нужны, необходимо в &lt;code&gt;catch&lt;/code&gt;-блоке написать комментарий, почему exception проигнорирован.&lt;/p&gt;&lt;br /&gt;
&lt;p&gt;Впереди две последние главы - о многопоточности и сериализации. Не переключайте канал.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-6498004365902175477?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/-j28dmRqFLY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/6498004365902175477/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/04/effective-java-exceptions.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6498004365902175477?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6498004365902175477?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/-j28dmRqFLY/effective-java-exceptions.html" title="Effective Java: Exceptions" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/04/effective-java-exceptions.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AARXYzeCp7ImA9WhZTFk4.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-4441232222513588570</id><published>2011-03-20T17:35:00.000+03:00</published><updated>2011-03-20T17:35:44.880+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-20T17:35:44.880+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="игры" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><title>Старые игры на новых виндах</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;p&gt;Есть такая проблема при запуске старых игр (например, Fallout 2 или Diablo 2) в Windows 7 или Vista - глючит цветопередача. На картинке есть области, где цвет как будто инвертирован (зелёный вместо чёрного и т. д.). Так вот, сегодня узнал простое решение проблемы - надо убить explorer перед запуском игры. Эти игры используют 256 цветов, а новый explorer работает с 32х битной палитрой. Поэтому они DirectDraw поделить между собой не могут, или что-то типа того.&lt;/p&gt;&lt;p&gt;Напомню, что убить explorer можно из диспетчера задач (Ctrl+Alt+Delete / диспетчер задач), при этом отвалится рабочий стол и все окна. Запустить игру можно будет из командной строки (cmd). Чтобы вернуть explorer, в меню диспетчера задач найти &amp;laquo;Выполнить&amp;raquo; и набрать там explorer. Всю эту процедуру можно объединить в один скрипт, который можно взять &lt;a href ="http://go.hopx.net/2010/05/256-color-issues-with-directdraw-and.html"&gt;здесь&lt;/a&gt; или &lt;a href="http://download.cnet.com/Windows7-Game-Color-Issue-Patch/3000-18541_4-10967974.html"&gt;здесь&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-4441232222513588570?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/XOTsVicEMuA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/4441232222513588570/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/03/blog-post_20.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4441232222513588570?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4441232222513588570?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/XOTsVicEMuA/blog-post_20.html" title="Старые игры на новых виндах" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/03/blog-post_20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAFQHo9cCp7ImA9WhdQFkw.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-4529233710948055491</id><published>2011-03-04T17:37:00.003+03:00</published><updated>2011-08-18T01:31:51.468+04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-18T01:31:51.468+04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="перевод" /><category scheme="http://www.blogger.com/atom/ns#" term="безопасность" /><title>Хеширование паролей и соль</title><content type="html">&lt;div style="text-align: justify;"&gt;
&lt;i&gt;Данный текст является переводом статьи &lt;a href="http://www.adayinthelifeof.nl/2011/02/02/password-hashing-and-salting/"&gt;«Password hashing and salting»&lt;/a&gt; об основах безопасного хранения паролей.&lt;/i&gt;&lt;br /&gt;
Золотое правило безопасности – если нужно хранить пароли, скажем, в базе данных, то необходимо их хешировать. Достаточно ли это безопасно? Спросите опытного человека, и он посоветует добавить &lt;a href="http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%BB%D1%8C_%28%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%8F%29"&gt;соль&lt;/a&gt;. Зачем? - спросите вы. – Потому что это сделает пароль длиннее и безопаснее.&lt;br /&gt;
Действительно, добавление соли улучшает безопасность, но не только потому, что пароли становятся длиннее. А потому, что вступает в игру другой (возможно, более существенный) фактор: солёные пароли более устойчивы к атакам с помощью баз данных хешей и радужных таблиц. Обо всём этом - далее.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Хеширование&lt;/b&gt;&lt;br /&gt;
Хеш-функция – односторонняя функция, преобразующая входной поток данных любого объёма (в нашем случае - пароль) в некоторую строку фиксированной длины. Односторонняя, потому что мы можем преобразовать исходные данные в хеш, но не можем по хешу восстановить исходные данные. Существует много хеш-функций хороших и плохих, быстрых и медленных. Всё, что нам нужно сейчас знать – это то, что в результате все они выдают хеш фиксированной длины (какова эта длина - зависит от хеш-функции). Это означает, что может существовать несколько исходных текстов, которым соответствует один и тот же хеш. Такие совпадения называются коллизиями; они довольно редки, но случаются.&lt;br /&gt;
Ещё более важная вещь, которую нужно понимать – то, что не существует математического способа восстановить исходный текст по хешу. Это возможно сделать только перебором – вычислить хеш для каждой перебираемой строки и сравнить с данным.&lt;br /&gt;
Чтобы проверить правильность введённого пароля, нужно посчитать его хеш и сравнить с тем, что лежит в базе данных. Псевдокод:&lt;br /&gt;
&lt;pre style="background: #ffffff; color: black;"&gt;if (sha1(suppliedPassword) ==
    "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4") &lt;span style="color: purple;"&gt;{&lt;/span&gt; 
    print &lt;span style="color: #0000e6;"&gt;"You have typed to correct password!"&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;/pre&gt;
Строка «e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4» - хеш секретного пароля, поэтому сообщение будет напечатано только в случае ввода правильного пароля. Здесь используется хеш-функция sha1.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Брутфорс&lt;/b&gt;&lt;br /&gt;
На самом деле, если вы очень хотите узнать правильный пароль из этого псевдокода, можете вбить хеш в Google и сразу найдёте ответ.&lt;br /&gt;
Предположим, нам известно, что пароль состоит из 6 строчных латинских букв. Тогда мы можем написать небольшой скрипт, перебирающий все такие строки от «aaaaaa» до «zzzzzz». Для каждой строки он будет вычислять sha1-хеш и сравнивать с «e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4». Если совпало, значит, правильный пароль найден. Это называется брутфорсом (brute-force) хеша, и на данный момент это единственный известный способ узнать пароль.&lt;br /&gt;
Теперь предположим, что наша система принимает, например, только пароли, состоящие из 4-8 строчных латинских букв. Кто-то нехороший украл нашу базу данных с логинами и хешами паролей пользователей. Это очень плохо, потому что с помощью брутфорса он может получить пароли ко всем аккаунтам.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Соль&lt;/b&gt;&lt;br /&gt;
Стоит сразу отметить, что как только кто-нибудь получит списки хешей, они смогут рано или поздно узнать пароли. Единственное противодействие, которое мы можем оказать – максимально усложнить перебор паролей, чтобы он стал неэффективным для недоброжелателей.&lt;br /&gt;
Мы можем сделать это двумя способами:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Заставить пользователей вводить очень длинные пароли (20-30 символов, например) с множеством спецсимволов.&lt;/li&gt;
&lt;li&gt;Усложнить пароли самостоятельно.&lt;/li&gt;
&lt;/ol&gt;
Понятно, что второй вариант гораздо проще осуществить. Для этого используется так называемая соль (salt). Прежде, чем посчитать хеш, мы добавим соль к паролю:&lt;br /&gt;
&lt;pre style="background: #ffffff; color: black;"&gt;saltedPasswordHash = sha1(SALT + password)&lt;span style="color: #808030;"&gt;;&lt;/span&gt;
&lt;/pre&gt;
Что это даёт? Прежде всего, то, что если кто-то установит пароль «1234», а солью будет строка «NaCl», то для взлома уже недостаточно будет перебрать все четырёхсимвольные последовательности. Восьмисимвольных паролей в миллионы раз больше, во столько же раз и перебор будет дольше.&lt;br /&gt;
Добавление соли происходит прозрачно для пользователя, но не для атакующего. Итак, мы получили очень простой способ обезопаситься, однако всё же не стоит на него полностью полагаться.&lt;br /&gt;
Потому что хакер может всё же узнать строку-соль, получив наши исходные коды (невозможно? А как они базы данных крадут?). В этом случае перебор становится вновь простым, как будто никакой соли и не было. По этому поводу важное правило: для начала убедитесь, что ваши пароли достаточно сложные. Соль не поможет плохому паролю, разве что против онлайн баз данных хешей.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Взлом с помощью онлайн баз данных хешей&lt;/b&gt;&lt;br /&gt;
В интернете существуют большие базы данных, где можно ввести хеш и получить исходный текст (конечно, в них есть далеко не все комбинации, но базы постоянно растут). Например, &lt;a href="http://hashcrack.com/"&gt;http://hashcrack.com/&lt;/a&gt;.&lt;br /&gt;
Вернёмся к соли. Велика вероятность, что в базе найдётся хеш для «1234», но не найдётся для «NaCl1234» (хотя и такие можно найти, поэтому лучше использовать соль посложнее). Таким образом, хакер не сможет воспользоваться базами данных для получения паролей, и ему придётся действительно перебирать все варианты. Фокус в том, что строку-соль даже не обязательно держать в секрете (хотя так ещё надёжнее).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Радужные таблицы&lt;/b&gt;&lt;br /&gt;
Однако и это ещё не всё. Фиксированная соль не помогает при взломе при помощи так называемых &lt;a href="http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B4%D1%83%D0%B6%D0%BD%D0%B0%D1%8F_%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0"&gt;радужных таблиц&lt;/a&gt;. Радужные таблицы – большие наборы хешей, которые могут быть сгенерированы достаточно быстро. С помощью радужных таблиц и известной соли можно сгенерировать свою базу данных хешей и паролей, которую затем использовать для взлома. Поскольку все пароли защищены одинаковой строкой-солью, то необходима только одна такая база для взлома всех аккаунтов. Конечно, сгенерировать такую базу не просто, но возможно.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Больше соли&lt;/b&gt;&lt;br /&gt;
Но и от этого мы можем защититься: будем использовать разную соль для разных аккаунтов.&lt;br /&gt;
&lt;pre style="background: #ffffff; color: black;"&gt;sha1('NaCl-&lt;b&gt;ujasdfas&lt;/b&gt;-1234')
    == b9afc2380b4fccef85b3f3da3379d220f1548cad
sha1('NaCl-&lt;b&gt;jubdsdsb&lt;/b&gt;-1234')
    == bd3a831fcd202b546307be8ea5b4a76c87700c4e
sha1('NaCl-&lt;b&gt;jehnwnad&lt;/b&gt;-secret123')
    == c0678ee585f635b9bbd91cf7b2a5597e8745521c
&lt;/pre&gt;
Первая часть пароля – фиксированная соль. Она теперь не очень нужна, но мы всё же её оставим. Вторая часть, выделенная жирным, - переменная соль, своя у каждого аккаунта. Третья часть – пароль пользователя.&lt;br /&gt;
Как же получить переменную соль для проверки пароля? Очень просто, её можно хранить в открытом виде в базе аккаунтов. Даже если хакер получит базу данных, ему придётся генерировать разные радужные таблицы для взлома каждого аккаунта. Ещё один профит от использования переменной соли – если два пользователя введут одинаковые пароли, хранимые хеши всё равно будут разными (см. первый и второй пароль в примере).&lt;br /&gt;
Ура, теперь одной радужной таблицей не взломать все аккаунты сразу!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Заключение&lt;/b&gt;&lt;br /&gt;
К сожалению, нет стопроцентного способа защитить свои хеши. Всегда возможно взломать хеши брутфорсом, но, следуя перечисленным советам, можно сделать этот процесс сложным и долгим.  Но даже это не остановит хакера, охотящегося за одним аккаунтом (root или Administrator, например). Поэтому убедитесь, что ваши пароли достаточно сложны, чтобы сделать брутфорс длительным. Регулярно меняйте пароли, чтобы к моменту завершения брутфорса взломанный пароль был бы уже не актуален.&lt;br /&gt;
И напоследок ещё несколько советов:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Все пароли должны удовлетворять определённым требованиям безопасности (зависит от приложения, но 8+ букв и спецсимволов почти всегда достаточно).&lt;/li&gt;
&lt;li&gt;Пароли должны хешироваться хорошей хеш-функцией (sha1 или лучшей, но не md5).&lt;/li&gt;
&lt;li&gt;Пароли должны хешироваться с хорошей переменной солью.&lt;/li&gt;
&lt;li&gt;Читайте про информационную безопасность. Это очень сложная, но и очень важная область.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-4529233710948055491?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/TPba9f25JkU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/4529233710948055491/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/03/blog-post.html#comment-form" title="Комментарии: 2" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4529233710948055491?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4529233710948055491?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/TPba9f25JkU/blog-post.html" title="Хеширование паролей и соль" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/03/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cGR3YycSp7ImA9Wx9bEU8.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-7282150669859444567</id><published>2011-02-19T18:23:00.000+03:00</published><updated>2011-02-19T18:23:46.899+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-19T18:23:46.899+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="general programming" /><title>Effective Java: General Programming (2/2)</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;b&gt;Item 51. Конкатенация строк медленна.&lt;/b&gt;&lt;br /&gt;
Конкатенация ("+") n строк выполняется за время n&lt;sup&gt;2&lt;/sup&gt; - следствие того, что строки в Java неизменяемы (immutable); когда соединяются две строки, содержимое обеих полностью копируется в новую. Поэтому если требуется объединить большое или заранее неизвестное количество строк, рекомендуется использовать &lt;code&gt;StringBuilder&lt;/code&gt; (есть ещё &lt;code&gt;StringBuffer&lt;/code&gt;, но он синхронизован, поэтому медленнее).&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 52. Ссылайтесь на объекты посредством их интерфейсов.&lt;/b&gt;&lt;br /&gt;
Если существует подходящий интерфейс, то лучше объявлять все параметры, возвращаемые значения, переменные и поля именно этим интерфейсом, а не имплементирующим классом.&lt;br /&gt;
Хорошо:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;List&amp;lt;Subscriber&gt; subscribers = new Vector&amp;lt;Subscriber&gt;()&lt;span style='color:#808030; '&gt;;&lt;/span&gt;
&lt;/pre&gt;Плохо:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;Vector&amp;lt;Subscriber&gt; subscribers = new Vector&amp;lt;Subscriber&gt;()&lt;span style='color:#808030; '&gt;;&lt;/span&gt;
&lt;/pre&gt;Это делает код более гибким, позволяет сменить имплементацию изменением всего одной строки. Исключения составляют те случаи, когда используются методы, специфичные для  имплементации, либо код полагается на некоторые особые свойства имплементации (например, потокобезопасность &lt;code&gt;Vector&lt;/code&gt;-а).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 53. Предпочитайте интерфейсы вместо reflection.&lt;/b&gt;&lt;br /&gt;
Суть в следующем: reflection - весьма небезопасная и малопроизводительная вещь, к тому же ещё и редко необходимая. Но если уж так случилось, что без неё никуда, то лучше хотя бы ограничить её использование. В большинстве программ, использующих недоступные в compile time классы, существует некоторый интерфейс или суперкласс, через которые можно ссылаться на экземпляры этого недоступного класса. То есть предлагается создавать экземпляры через reflection, а затем работать с ними через интерфейс или суперкласс, как с любыми другими объектами.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 54. Применяйте нативные (native) методы с умом.&lt;/b&gt;&lt;br /&gt;
Нативные методы имеют 3 основных назначения:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Обеспечение доступа к платформо-зависимым средствам.&lt;br /&gt;
В целом допустимо использовать нативные методы для этого, хотя Java платформа с каждой новой версией постепенно избавляет от такой необходимости.&lt;/li&gt;
&lt;li&gt;Возможность использовать устаревшие (legacy) библиотеки.&lt;br /&gt;
Тоже допустимо.&lt;/li&gt;
&lt;li&gt;Увеличение производительности приложения.&lt;br /&gt;
В старых версиях Java и JVM это имело смысл, сейчас - практически нет. Java стала &lt;i&gt;намного&lt;/i&gt; быстрее, большинство задач можно решить без нативных методов без значительных потерь в производительности.&lt;/li&gt;
&lt;/ol&gt;Использование нативных методов имеет много минусов: это небезопасно, платформо-зависимо и может даже &lt;i&gt;ухудшить&lt;/i&gt; производительность.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 55. Оптимизируйте с умом.&lt;/b&gt;&lt;br /&gt;
Преждевременная оптимизация - зло. Не нужно ничего оптимизировать, пока не получено правильное и надёжное, хоть и медленное, решение. Если программа хорошо спроектирована, отдельные модули можно будет оптимизировать позже, без изменений в других модулях.&lt;br /&gt;
И, конечно, когда действительно приходит время для оптимизации, нужно сначала выяснить (например, с помощью профайлера), в каком месте программа тратит больше всего времени. Народная мудрость: 80% времени программа проводит в 20% кода.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 56. Соблюдайте всеобщие соглашения о наименованиях (naming conventions).&lt;/b&gt;&lt;br /&gt;
Платформа Java имеет устоявшиеся принципы именования &lt;i&gt;всего&lt;/i&gt; (пакетов, классов, интерфейсов, методов, ...), большую часть которых можно найти в &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.8"&gt;Java Language Specification (6.8)&lt;/a&gt;. Рекомендуется их строго соблюдать и не нарушать без веской на то причины, иначе поддерживать ваш код и использовать его API будет затруднительно.&lt;br /&gt;
Данный параграф содержит эти принципы, переписывать частично или полностью смысла нет.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-7282150669859444567?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/gC3Fl5tTJ2M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/7282150669859444567/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/02/effective-java-general-programming-22.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7282150669859444567?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7282150669859444567?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/gC3Fl5tTJ2M/effective-java-general-programming-22.html" title="Effective Java: General Programming (2/2)" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/02/effective-java-general-programming-22.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQBQ3o4fSp7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-1138511532622505819</id><published>2011-01-19T21:39:00.000+03:00</published><updated>2011-01-19T21:39:12.435+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:39:12.435+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="general programming" /><title>Effective Java: General Programming (1/2)</title><content type="html">&lt;div style="text-align: justify;"&gt;Эта глава книги Effective Java собрала более общие советы по написанию кода на Java (и не только). Параграфов довольно много, поэтому я разбил свой сжатый пересказ на две части.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 45. Минимизируйте область видимости локальных переменных.&lt;/b&gt;&lt;br /&gt;
Это улучшает читабельность кода и уменьшает число потенциальных ошибок.&lt;br /&gt;
Прежде всего, по возможности объявлять локальную переменную надо там, где она впервые используется. Далее, почти все объявления локальных переменных должны содержать инициализацию. Исключение - когда инициализацию нужно поместить в &lt;code&gt;try/catch&lt;/code&gt; блок, а сама переменная нужна снаружи него.&lt;br /&gt;
Отдельно следует отметить циклы. Цикл &lt;code&gt;for&lt;/code&gt; предоставляет возможность объявлять переменные цикла (loop variables) доступными только для тела самого цикла, что делает его более предпочтительным, нежели циклы &lt;code&gt;while&lt;/code&gt;.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 46. Предпочитайте &lt;code&gt;for-each&lt;/code&gt; циклы вместо &lt;code&gt;for&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
Опять же, это делает код более читабельным и уменьшает шансы ошибиться по невнимательности. Но есть и случаи, когда &lt;code&gt;for-each&lt;/code&gt; не подходит: фильтрация (когда нужно удалять элементы из коллекции, нужен явный итератор), трансформация (когда нужно заменять одни элементы списка или массива на другие, нужен явный итератор или переменная-индекс), параллельная итерация по нескольким коллекциям.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 47. Знайте и применяйте библиотеки.&lt;/b&gt;&lt;br /&gt;
Изобретать колёса не имеет смысл, потому что:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;это лишняя трата времени;&lt;/li&gt;
&lt;li&gt;вряд ли получится лучше, чем уже написано ранее;&lt;/li&gt;
&lt;li&gt;библиотеки совершенствуются без вашего участия.&lt;/li&gt;
&lt;/ul&gt;Полезно иногда смотреть в release notes новых версий библиотек.&lt;br /&gt;
Приведён хороший пример кривого колеса: самописная функция, возвращающая псевдослучайное число из интервала &lt;code&gt;[0, n)&lt;/code&gt;:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; int random(int n) &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; &lt;span style='color:#bb7977; font-weight:bold; '&gt;Math&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;abs&lt;span style='color:#808030; '&gt;(&lt;/span&gt;rnd&lt;span style='color:#808030; '&gt;.&lt;/span&gt;nextInt&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#808030; '&gt;%&lt;/span&gt; n&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;Функция выглядит нормально, но в ней скрыты целых три изъяна. Предлагается попробовать поискать их самостоятельно, однако два их них весьма нетривиальны (я-то их сам точно не нашёл бы). Эти недостатки перечислены в конце поста.&lt;br /&gt;
Вместо такой функции следует использовать &lt;code&gt;Random.nextInt(int)&lt;/code&gt;, где этих проблем нет.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 48. Избегайте &lt;code&gt;float&lt;/code&gt; и &lt;code&gt;double&lt;/code&gt;, если нужны точные результаты.&lt;/b&gt;&lt;br /&gt;
Типы &lt;code&gt;float&lt;/code&gt; и &lt;code&gt;double&lt;/code&gt; представляют собой числа с плавающей запятой (floating point). Это означает, что они хранят не точное значение числа, а максимально близкое к нему приближение. Например, они не могут точно хранить числа &lt;code&gt;0.1&lt;/code&gt;, &lt;code&gt;0.01&lt;/code&gt;, &lt;code&gt;0.001&lt;/code&gt; и т.д. Если задача требует точных результатов, лучше использовать &lt;code&gt;BigDecimal&lt;/code&gt; (хоть они и менее удобны и быстры, чем примитивы), либо сводить эту задачу к целым числам (например, считать деньги не в рублях, а копейках).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 49. Предпочитайте примитивы вместо объектных типов.&lt;/b&gt;&lt;br /&gt;
&lt;small&gt;(здесь и далее под объектным типом подразумевается объектная обёртка примитива (boxed primitive))&lt;/small&gt;&lt;br /&gt;
Автобоксинг и автоанбоксинг (Java 1.5) размыл, но не стёр различия между ними. А различия таковы:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;у объектных типов могут существовать разные экземпляры с одинаковыми значениями, что не позволяет сравнивать их между собой с помощью &lt;code&gt;==&lt;/code&gt;, как примитивы;&lt;/li&gt;
&lt;li&gt;объектные типы допускают дополнительное нефункциональное значение &lt;code&gt;null&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;примитивы экономичнее в плане производительности и использования памяти.&lt;/li&gt;
&lt;/ul&gt;Когда следует применять объектные типы:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;при работе с коллекциями и другими параметризированными классами;&lt;/li&gt;
&lt;li&gt;при рефлексивном (reflective) вызове методов.&lt;/li&gt;
&lt;/ul&gt;В остальных случаях, когда есть выбор, рекомендуется применять примитивы. Если приходится иметь дело с объектными типами, следует помнить:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;если программа сравнивает объектные типы с помощью &lt;code&gt;==&lt;/code&gt;, то сравниваются ссылки на объекты, что почти всегда не то, что вы хотите;&lt;/li&gt;
&lt;li&gt;когда в выражении замешаны и примитивы, и объектные типы, выполняется unboxing последних;&lt;/li&gt;
&lt;li&gt;unboxing может вызвать &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Item 50. Избегайте строк, если другие типы больше подходят.&lt;/b&gt;&lt;br /&gt;
Строки - не замена для других типов значений. Поступающая в программу информация, будь то чтение из файла, обмен по сети или ввод с клавиатуры, чаще всего приходит именно в текстовом виде и должна храниться в &lt;code&gt;String&lt;/code&gt; только если действительно представляет собой некоторый текст. Если же есть более подходящий тип для данных (числовые типы, &lt;code&gt;boolean&lt;/code&gt;, ...), нужно использовать его.&lt;br /&gt;
Строки - не замена для &lt;code&gt;enum&lt;/code&gt;-констант. Об этом было в Item 30.&lt;br /&gt;
Строки - не замена для составных типов. Так делать плохо:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;String compoundKey = className + "#" + i.next()&lt;span style='color:#808030; '&gt;;&lt;/span&gt;
&lt;/pre&gt;Для составных типов лучше писать составные классы.&lt;br /&gt;
Строки не годятся для предоставления доступа к чему-либо. Имеется в виду то, что, например, строки нехорошо использовать в качестве ключей доступа к определённым данным в том случае, если клиентский код может нарушить целостность этих данных, предоставив неправильный или &amp;laquo;чужой&amp;raquo; ключ.&lt;br /&gt;
&lt;br /&gt;
&lt;hr&gt;&lt;br /&gt;
Далее спойлер (см. Item 47)&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
.&lt;br /&gt;
&lt;br /&gt;
Три изъяна функции из Item 47:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Если &lt;code&gt;rnd.nextInt()&lt;/code&gt; выдаст &lt;code&gt;Integer.MIN_VALUE&lt;/code&gt;, то функция вернёт отрицательное значение.&lt;/li&gt;
&lt;li&gt;Если &lt;code&gt;n&lt;/code&gt; - малая степень двойки, то последовательность генерируемых чисел довольное скоро начнёт повторять саму себя.&lt;/li&gt;
&lt;li&gt;Если &lt;code&gt;n&lt;/code&gt; - не степень двойки, то некоторые псевдослучайные числа будут генерироваться чаще других.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-1138511532622505819?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/jsNOrZWG1ks" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/1138511532622505819/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/01/effective-java-general-programming-12.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1138511532622505819?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1138511532622505819?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/jsNOrZWG1ks/effective-java-general-programming-12.html" title="Effective Java: General Programming (1/2)" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/01/effective-java-general-programming-12.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUHR3o5eip7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-5970834846144324655</id><published>2011-01-11T01:56:00.002+03:00</published><updated>2011-01-19T21:53:56.422+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:53:56.422+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gnu/linux" /><title>Nautilus: сортировка файлов по имени</title><content type="html">&lt;div style="text-align: justify;"&gt;А вы знали, как хитро Наутилус сортирует файлы по имени?&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_bi7O1kq4qXc/TSuIdWU1ZPI/AAAAAAAAAQU/tGxL8ZMdU9c/s1600/Screenshot-sort+-+File+Browser-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_bi7O1kq4qXc/TSuIdWU1ZPI/AAAAAAAAAQU/tGxL8ZMdU9c/s1600/Screenshot-sort+-+File+Browser-2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Помимо всего прочего, Наутилус умеет выделять из имён файлов числа и упорядочивать их именно как числа, а не как последовательность символов (см. последние три файла).&lt;br /&gt;
&lt;br /&gt;
Это всё прекрасно и очень человечно, но начало мешать. Моя видеокамера (не столь человечная) нумерует файлы шестнадцатеричными числами, в результате чего они у меня неправильно сортируются. И что самое плохое - я пока не нашёл решения этой проблемы для Наутилуса (переходить на другие менеджеры только из-за этого не хочется). Смена значения &lt;code&gt;$LC_COLLATE&lt;/code&gt; не помогает, так как локаль здесь вообще ни при чём.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-5970834846144324655?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/PuYAzU3-maQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/5970834846144324655/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/01/nautilus.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/5970834846144324655?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/5970834846144324655?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/PuYAzU3-maQ/nautilus.html" title="Nautilus: сортировка файлов по имени" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_bi7O1kq4qXc/TSuIdWU1ZPI/AAAAAAAAAQU/tGxL8ZMdU9c/s72-c/Screenshot-sort+-+File+Browser-2.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/01/nautilus.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cFR38-fyp7ImA9Wx9XFE4.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-2101141452087262074</id><published>2011-01-08T00:16:00.000+03:00</published><updated>2011-01-08T00:16:56.157+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-08T00:16:56.157+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="забавно" /><title>Do not touch the colon</title><content type="html">&lt;div style="text-align: justify;"&gt;Увидел &lt;a href="http://antilamer.livejournal.com/342207.html"&gt;у antilamer-а&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Mark&lt;/b&gt; writes, "advice that is true for life as well as code."&lt;br /&gt;
&lt;code&gt;# The colon is very important. DO NOT TOUCH.&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Colon одновременно означает двоеточие и толстую кишку. Буду знать.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-2101141452087262074?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/6blqf7Bl9IU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/2101141452087262074/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2011/01/do-not-touch-colon.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2101141452087262074?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2101141452087262074?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/6blqf7Bl9IU/do-not-touch-colon.html" title="Do not touch the colon" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2011/01/do-not-touch-colon.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMGR34-eyp7ImA9Wx9QF08.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-7763748091810537640</id><published>2010-12-30T18:37:00.000+03:00</published><updated>2010-12-30T18:37:06.053+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-30T18:37:06.053+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="android" /><category scheme="http://www.blogger.com/atom/ns#" term="приключения" /><title>Приключение в коде</title><content type="html">&lt;div style="text-align: justify;"&gt;На днях со мной произошло следующее приключение в коде приложения для android. В этом приложении мне нужно иметь общий объект-ядро, доступный из любого &lt;code&gt;Activity&lt;/code&gt;, поэтому я отнаследовался от &lt;code&gt;Application&lt;/code&gt; и стал хранить этот объект в новом классе. Объект-ядро нужно инициализировать, в процессе чего оно обращается к базе данных. Всё это выглядело следующим образом:&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;final&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; MyApplication &lt;span style='color:#800000; font-weight:bold; '&gt;extends&lt;/span&gt; Application &lt;span style='color:#800080; '&gt;{&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;private&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;final&lt;/span&gt; Core core&lt;span style='color:#800080; '&gt;;&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; MyApplication&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;super&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
        core &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Core&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;this&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
        core&lt;span style='color:#808030; '&gt;.&lt;/span&gt;init&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt; &lt;span style='color:#696969; '&gt;// здесь обращаемся к бд&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; Core getCore&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; core&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;(здесь и далее - упрощённый код)&lt;br /&gt;
&lt;br /&gt;
Но была проблема: мой &lt;code&gt;SQLiteOpenHelper&lt;/code&gt; отказывался давать мне доступ к базе данных внутри &lt;code&gt;core.init()&lt;/code&gt;: вызовы &lt;code&gt;getReadableDatabase&lt;/code&gt; и &lt;code&gt;getWritableDatabase&lt;/code&gt; кидали недокументированные &lt;code&gt;NullPointerException&lt;/code&gt;-ы.&lt;br /&gt;
&lt;br /&gt;
Проблема оказалась в том, что после вызова конструктора суперкласса в &lt;code&gt;MyApplication&lt;/code&gt;, экземпляр последнего(также известный как application context) ещё не был готов к работе. Коллега подсказал использовать хук &lt;code&gt;onCreate()&lt;/code&gt; для инициализации &lt;code&gt;core&lt;/code&gt; и это помогло. В конечном итоге это выглядит так:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;final&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; MyApplication &lt;span style='color:#800000; font-weight:bold; '&gt;extends&lt;/span&gt; Application &lt;span style='color:#800080; '&gt;{&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;private&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;final&lt;/span&gt; Core core&lt;span style='color:#800080; '&gt;;&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; MyApplication&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;super&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
        core &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Core&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;this&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#808030; '&gt;@&lt;/span&gt;Override
    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#bb7977; '&gt;void&lt;/span&gt; onCreate&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        core&lt;span style='color:#808030; '&gt;.&lt;/span&gt;init&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#696969; '&gt;// здесь обращаемся к бд&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; Core getCore&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; core&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
И прекрасно работает.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-7763748091810537640?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/rR34wNdR5ms" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/7763748091810537640/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/12/blog-post_30.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7763748091810537640?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7763748091810537640?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/rR34wNdR5ms/blog-post_30.html" title="Приключение в коде" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/12/blog-post_30.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4CRnc8eip7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-4222350872977807328</id><published>2010-12-14T00:29:00.002+03:00</published><updated>2011-01-19T21:49:27.972+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:49:27.972+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Методы</title><content type="html">&lt;div style="text-align: justify;"&gt;Переходим к следующей главе книги.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 38. Проверяйте параметры на корректность.&lt;/b&gt;&lt;br /&gt;
Большинство методов и конструкторов имеют некоторые ограничения на передаваемые им параметры. Проверка корректности этих параметров позволяет обнаруживать проблемы как можно раньше, что облегчает её исправление.&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Для публичных методов и конструкторов лучше всего сразу проверять параметры и кидать соответствующие exception-ы, если они некорректны. Обычно это бывают &lt;code&gt;IllegalArgumentException&lt;/code&gt;, &lt;code&gt;IndexOutOfBoundsException&lt;/code&gt; или &lt;code&gt;NullPointerException&lt;/code&gt;. Ограничения на параметры и exception-ы, которые кидаются при их нарушении должны быть задокументированы.&lt;br /&gt;
Для неэкспортируемых (закрытых) методов и конструкторов вы, как автор пакета, сами отвечаете за корректность передаваемых параметров и должны использовать только assertions для их проверки.&lt;br /&gt;
Есть и исключения из этих правил. Одно из них - когда проверка корректности слишком сложна и затратна &lt;i&gt;и&lt;/i&gt; она происходит неявно во время выполнения метода. Пример такой ситуации - сортировка списка &lt;code&gt;Collections.sort(List)&lt;/code&gt;, который может содержать несравниваемые элементы. Иногда в таких случаях полезно применять идиому перевода исключений (exception translation idiom), чтобы клиентский код всегда получал понятное исключение вроде &lt;code&gt;IllegalArgumentException&lt;/code&gt; вместо того, которое порождается внутри закрытого кода.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 39. Делайте защитные копии (defensive copies), когда нужно.&lt;/b&gt;&lt;br /&gt;
Здесь название говорит сам за себя. Вообще, программировать нужно так, как будто все клиенты только и будут пытаться нарушить инварианты ваших классов.&lt;br /&gt;
Защитные копии - ещё одна причина использовать неизменяемые (immutable) объекты в качестве компонентов.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 40. Проектируйте сигнатуры методов внимательно.&lt;/b&gt;&lt;br /&gt;
Здесь собраны советы, не вошедшие в другие параграфы.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Выбирайте наиболее подходящие имена для методов.&lt;/li&gt;
&lt;li&gt;Не нужно слишком много "удобных" методов. Для каждого действия, обеспечиваемого классом или интерфейсом, пишите ровно один полнофункциональный метод. Особенно это касается интерфейсов. Добавляйте укороченный метод только если он будет часто использоваться.&lt;/li&gt;
&lt;li&gt;Избегайте большого числа параметров. Лучше всего, когда их не больше четырёх. Три способа уменьшить их количество: разбить метод на несколько, создать вспомогающий класс, группирующий часть параметров, использовать шаблон Builder.&lt;/li&gt;
&lt;li&gt;В типах параметров предпочитайте интерфейсы вместо имплементирующих классов.&lt;/li&gt;
&lt;li&gt;Предпочитайте двухэлементый &lt;code&gt;enum&lt;/code&gt; вместо &lt;code&gt;boolean&lt;/code&gt;-параметра, где возможно. Например, если конструктор класса &lt;code&gt;Thermometer&lt;/code&gt; принимает параметр, определяющий единицу измерения температуры, то лучше единицы измерения засунуть в &lt;code&gt;enum&lt;/code&gt;, нежели выбирать одну в случае &lt;code&gt;true&lt;/code&gt; и вторую в случае &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Item 41. Используйте перегрузку (overload) осторожно.&lt;/b&gt;&lt;br /&gt;
В отличие от переопределения (override), перегрузка работает контринтуитивно: выбор метода происходит во время компиляции, а не в рантайме. Поэтому перегрузку следует применять только там, где этот выбор очевиден. Лучше всего, когда все взаимоперегружающие методы имеют разное количество параметров.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 42. Используйте varargs разумно.&lt;/b&gt;&lt;br /&gt;
Varargs - аргументы переменной длины. При замене аргументов метода на varargs следует учесть все возможные последствия, поскольку некоторые не компилируемые ранее вызовы метода станут допустимыми. Кроме того, не стоит забывать о возможной потере в производительности. Один из вариантов обойти эту потерю - предоставить отдельные методы для 1, 2, 3, ... аргументов и отдельный с varargs.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 43. Возвращайте пустые массивы и коллекции, а не &lt;code&gt;null&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
Возвращать &lt;code&gt;null&lt;/code&gt; вместо пустого массива или коллекции нет смысла. Это лишь добавляет лишний код в методе и лишний код для обработки его возвращаемого значения. Если создавать пустую коллекцию или массив слишком дорого, то можно их кэшировать.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 44. Пишите комментарии к каждому экспортируемому элементу API.&lt;/b&gt;&lt;br /&gt;
Вряд ли кто-нибудь станет с этим спорить. Про утилиту javadoc знают почти все, а этот параграф посвящает в основы документирования API для последующего её применения.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-4222350872977807328?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/w0HkQ-UgkMI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/4222350872977807328/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/12/effective-java.html#comment-form" title="Комментарии: 2" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4222350872977807328?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4222350872977807328?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/w0HkQ-UgkMI/effective-java.html" title="Effective Java: Методы" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/12/effective-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIGRn07eSp7ImA9Wx9RFk8.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-2765758977435729649</id><published>2010-12-03T18:35:00.003+03:00</published><updated>2010-12-18T02:12:07.301+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-18T02:12:07.301+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="рекомендую" /><title>How machines work</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;a href="http://press.discovery.com/emea/dsc/programs/how-machines-work/"&gt;How machines work&lt;/a&gt; - интереснейшая телепередача канала Discovery.&lt;br /&gt;
&lt;br /&gt;
Современный ткацкий станок, эскалатор, машинка для нанесения татуировок, автомат для установки кеглей и транспортировки шаров в боулинге, судно на воздушной подушке - вот малая часть тех машин, об устройстве которых рассказывается в телепередаче. Очень рекомендую.&lt;br /&gt;
&lt;br /&gt;
Серии легко найти на торрентах, например, &lt;a href="http://rutor.org/search/How%20machines%20work"&gt;вот&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UPD. 1&lt;/b&gt; Забыл сказать. В русском переводе у них там иногда случаются заскоки типа "биллиона людей" или "стекло усиливает солнечный свет", поэтому надо слушать внимательно и вдумываться. Но это редко попадается. В целом очень полезно.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UPD. 2&lt;/b&gt; Дорогие переводчики! Послушайте меня! В России не применяется слово "биллион"! Нет у нас такого числа! Америкаский billion = миллиард! Английский billion = триллион!&lt;br /&gt;
Обидно, что даже Футурама в переводе Ren-TV очень сильно этим грешит.&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-2765758977435729649?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/PjsMBNoF-Zc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/2765758977435729649/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/12/how-machines-work.html#comment-form" title="Комментарии: 1" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2765758977435729649?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2765758977435729649?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/PjsMBNoF-Zc/how-machines-work.html" title="How machines work" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/12/how-machines-work.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEINRHc8eyp7ImA9Wx9bGEw.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-1091801193426692752</id><published>2010-12-02T20:38:00.004+03:00</published><updated>2011-02-27T16:16:35.973+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-27T16:16:35.973+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="ооп" /><title>Перегрузка и переопределение: памятка</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;b&gt;Override&lt;/b&gt; - переопределение - когда подкласс подсовывает свою реализацию метода вместо реализации в суперклассе. При вызове метода выбирается наиболее "специфическая" реализация, то есть реализация в подклассе, если она есть, приоритетнее реализации в суперклассе. В Java выбор выполняемого метода при переопределении происходит &lt;i&gt;динамически&lt;/i&gt; (в рантайме) и не зависит от того, каким типом объявлена ссылка на объект:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; TestOverriding &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
    
    &lt;span style='color:#800000; font-weight:bold; '&gt;private&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; Parent &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;String&lt;/span&gt; getName&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; &lt;span style='color:#0000e6; '&gt;"Parent"&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt; &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;private&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; Child &lt;span style='color:#800000; font-weight:bold; '&gt;extends&lt;/span&gt; Parent &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#808030; '&gt;@&lt;/span&gt;Override
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;String&lt;/span&gt; getName&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;return&lt;/span&gt; &lt;span style='color:#0000e6; '&gt;"Child"&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt; &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#bb7977; '&gt;void&lt;/span&gt; main&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#bb7977; font-weight:bold; '&gt;String&lt;/span&gt;&lt;span style='color:#808030; '&gt;[&lt;/span&gt;&lt;span style='color:#808030; '&gt;]&lt;/span&gt; args&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        Parent child &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; Child&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
        &lt;span style='color:#696969; '&gt;// Prints "Child"&lt;/span&gt;
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;System&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;out&lt;span style='color:#808030; '&gt;.&lt;/span&gt;println&lt;span style='color:#808030; '&gt;(&lt;/span&gt;child&lt;span style='color:#808030; '&gt;.&lt;/span&gt;getName&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt; 
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Overload&lt;/b&gt; - перегрузка - объявление методов (или конструкторов) с одинаковыми именами, но разными с сигнатурами. Пример - все конструкторы любого класса, если их больше одного. В Java выбор выполняемого метода при перегрузке происходит &lt;i&gt;статически&lt;/i&gt; (во время компиляции) и не зависит от типа объекта в рантайме:&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;&lt;span style='color:#800000; font-weight:bold; '&gt;import&lt;/span&gt;&lt;span style='color:#004a43; '&gt; java&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;util&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;Collection&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800000; font-weight:bold; '&gt;import&lt;/span&gt;&lt;span style='color:#004a43; '&gt; java&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;util&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;HashSet&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
&lt;span style='color:#800000; font-weight:bold; '&gt;import&lt;/span&gt;&lt;span style='color:#004a43; '&gt; java&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;util&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;&lt;span style='color:#004a43; '&gt;Set&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;

&lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;class&lt;/span&gt; TestOverloading &lt;span style='color:#800080; '&gt;{&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#bb7977; '&gt;void&lt;/span&gt; classifyCollection&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#bb7977; font-weight:bold; '&gt;Collection&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#808030; '&gt;?&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; c&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;System&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;out&lt;span style='color:#808030; '&gt;.&lt;/span&gt;println&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#0000e6; '&gt;"Collection"&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#bb7977; '&gt;void&lt;/span&gt; classifyCollection&lt;span style='color:#808030; '&gt;(&lt;/span&gt;Set&lt;span style='color:#808030; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#808030; '&gt;?&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; s&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;System&lt;/span&gt;&lt;span style='color:#808030; '&gt;.&lt;/span&gt;out&lt;span style='color:#808030; '&gt;.&lt;/span&gt;println&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#0000e6; '&gt;"Set"&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;

    &lt;span style='color:#800000; font-weight:bold; '&gt;public&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;static&lt;/span&gt; &lt;span style='color:#bb7977; '&gt;void&lt;/span&gt; main&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#bb7977; font-weight:bold; '&gt;String&lt;/span&gt;&lt;span style='color:#808030; '&gt;[&lt;/span&gt;&lt;span style='color:#808030; '&gt;]&lt;/span&gt; args&lt;span style='color:#808030; '&gt;)&lt;/span&gt; &lt;span style='color:#800080; '&gt;{&lt;/span&gt;
        &lt;span style='color:#bb7977; font-weight:bold; '&gt;Collection&lt;/span&gt;&lt;span style='color:#808030; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#808030; '&gt;?&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt; c &lt;span style='color:#808030; '&gt;=&lt;/span&gt; &lt;span style='color:#800000; font-weight:bold; '&gt;new&lt;/span&gt; HashSet&lt;span style='color:#808030; '&gt;&amp;lt;&lt;/span&gt;&lt;span style='color:#bb7977; font-weight:bold; '&gt;Object&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt;&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
        &lt;span style='color:#696969; '&gt;// prints "Collection"&lt;/span&gt;
        classifyCollection&lt;span style='color:#808030; '&gt;(&lt;/span&gt;c&lt;span style='color:#808030; '&gt;)&lt;/span&gt;&lt;span style='color:#800080; '&gt;;&lt;/span&gt;
    &lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;span style='color:#800080; '&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-1091801193426692752?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/jwwN5mk6Tu4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/1091801193426692752/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/12/blog-post.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1091801193426692752?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1091801193426692752?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/jwwN5mk6Tu4/blog-post.html" title="Перегрузка и переопределение: памятка" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/12/blog-post.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcAR3o7eCp7ImA9Wx9SEUw.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-6629386787840389110</id><published>2010-11-30T12:40:00.000+03:00</published><updated>2010-11-30T12:40:46.400+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-30T12:40:46.400+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>N things you didn't know about Java</title><content type="html">&lt;div style="text-align: justify;"&gt;На ibm.com есть &lt;a href="http://www.ibm.com/developerworks/views/java/libraryview.jsp?search_by=5+things+you+did"&gt;серия статей "5 things you didn't know about ..."&lt;/a&gt; о различных аспектах Java. Те вещи, которые показались мне наиболее интересными, я изложу здесь.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Iterator, you surprise me!&lt;/b&gt;&lt;br /&gt;
Не секрет, что многие используют итераторы очень часто, но когда вы в последний раз видели его интерфейс?&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Во-первых, итератор умеет удалять элементы из итерируемой коллекции. Это сделано, в основном, для избежания ошибок вроде &lt;code&gt;ConcurrentModifiedException&lt;/code&gt;, которые возникают при модификации коллекции, у которой есть незакрытые итераторы. Некоторые коллекции позволяют делать такие изменения, но в общем случае &lt;code&gt;Iterator.remove()&lt;/code&gt; безопаснее.&lt;br /&gt;
&lt;br /&gt;
Во-вторых, существует подинтерфейс итератора &lt;code&gt;ListIterator&lt;/code&gt;, поддерживаемый списками. Кроме всего прочего, он умеет добавлять элементы в список и осуществлять двунаправленный скроллинг.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Scanner&lt;/b&gt;&lt;br /&gt;
Класс &lt;code&gt;Scanner&lt;/code&gt; предназначен для парсинга текста и представляет простой API для его преобразования в стандартные типы данных Java. Приводится пример использования класса для парсинга списка задач такого типа:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
fetch 1 head&lt;br /&gt;
fetch 3 eye&lt;br /&gt;
fetch 1 foot&lt;br /&gt;
attach foot to head&lt;br /&gt;
attach eye to head&lt;br /&gt;
admire&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
Код будет выглядеть следующим образом:&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;Scanner scanner = new Scanner(commandFile)&lt;span style="color: #808030;"&gt;;&lt;/span&gt;
&lt;span style="color: dimgrey;"&gt;// Commands come in a verb/number/noun or verb form&lt;/span&gt;
while (scanner.hasNext()) &lt;span style="color: purple;"&gt;{&lt;/span&gt;
    &lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt; verb &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;next&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: maroon; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #808030;"&gt;(&lt;/span&gt;verb&lt;span style="color: #808030;"&gt;.&lt;/span&gt;equals&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"fetch"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        &lt;span style="color: #bb7977;"&gt;int&lt;/span&gt; num &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;nextInt&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt; type &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;next&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        fetch&lt;span style="color: #808030;"&gt;(&lt;/span&gt;num&lt;span style="color: #808030;"&gt;,&lt;/span&gt; type&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: purple;"&gt;}&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #808030;"&gt;(&lt;/span&gt;verb&lt;span style="color: #808030;"&gt;.&lt;/span&gt;equals&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"attach"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt; item &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;next&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt; to &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;next&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt; target &lt;span style="color: #808030;"&gt;=&lt;/span&gt; scanner&lt;span style="color: #808030;"&gt;.&lt;/span&gt;next&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        attach&lt;span style="color: #808030;"&gt;(&lt;/span&gt;item&lt;span style="color: #808030;"&gt;,&lt;/span&gt; target&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: purple;"&gt;}&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;if&lt;/span&gt; &lt;span style="color: #808030;"&gt;(&lt;/span&gt;verb&lt;span style="color: #808030;"&gt;.&lt;/span&gt;equals&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"admire"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        admire&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: purple;"&gt;}&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;else&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;System&lt;/span&gt;&lt;span style="color: #808030;"&gt;.&lt;/span&gt;out&lt;span style="color: #808030;"&gt;.&lt;/span&gt;println&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"I don't know how to "&lt;/span&gt; &lt;span style="color: #808030;"&gt;+&lt;/span&gt; verb
                &lt;span style="color: #808030;"&gt;+&lt;/span&gt; &lt;span style="color: #0000e6;"&gt;", marthter."&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Timer&lt;/b&gt;&lt;br /&gt;
Классы &lt;code&gt;java.util.Timer&lt;/code&gt; и &lt;code&gt;TimerTask&lt;/code&gt; представляют удобный способ выполнять задачи с задержкой или с некоторой периодичностью. Пример:&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;class&lt;/span&gt; Later
&lt;span style="color: purple;"&gt;{&lt;/span&gt;
    &lt;span style="color: maroon; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: #bb7977;"&gt;void&lt;/span&gt; main&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #bb7977; font-weight: bold;"&gt;String&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt; args&lt;span style="color: #808030;"&gt;)&lt;/span&gt;
    &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        Timer t &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;new&lt;/span&gt; Timer&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"TimerThread"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        t&lt;span style="color: #808030;"&gt;.&lt;/span&gt;schedule&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;new&lt;/span&gt; TimerTask&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
            &lt;span style="color: maroon; font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: #bb7977;"&gt;void&lt;/span&gt; run&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
                &lt;span style="color: #bb7977; font-weight: bold;"&gt;System&lt;/span&gt;&lt;span style="color: #808030;"&gt;.&lt;/span&gt;out&lt;span style="color: #808030;"&gt;.&lt;/span&gt;println&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"This is later"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
                &lt;span style="color: #bb7977; font-weight: bold;"&gt;System&lt;/span&gt;&lt;span style="color: #808030;"&gt;.&lt;/span&gt;exit&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
            &lt;span style="color: purple;"&gt;}&lt;/span&gt;
        &lt;span style="color: purple;"&gt;}&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt; &lt;span style="color: #008c00;"&gt;1&lt;/span&gt; &lt;span style="color: #808030;"&gt;*&lt;/span&gt; &lt;span style="color: #008c00;"&gt;1000&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        &lt;span style="color: #bb7977; font-weight: bold;"&gt;System&lt;/span&gt;&lt;span style="color: #808030;"&gt;.&lt;/span&gt;out&lt;span style="color: #808030;"&gt;.&lt;/span&gt;println&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;"Exiting main()"&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
    &lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
Следует обратить внимание, что &lt;code&gt;Timer&lt;/code&gt; создаёт обычный, не демонический поток, поэтому в данном примере для прекращения работы программы используется &lt;code&gt;System.exit&lt;/code&gt;. При использовании в сложных системах рекомендуется создавать поток-демон, который не принуждает виртуальную машину работать после завершения остальных процессов.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;SwingX&lt;/b&gt;&lt;br /&gt;
Иногда компонентов &lt;code&gt;Swing&lt;/code&gt; становится недостаточно, что частично компенсирует проект &lt;a href="https://swingx.dev.java.net/"&gt;SwingX&lt;/a&gt;. Возможности библиотеки SwingX включают:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;сортировка, фильтрование и подсветка текста для таблиц, деревьев, списков;&lt;/li&gt;
&lt;li&gt;поиск;&lt;/li&gt;
&lt;li&gt;автодополнение;&lt;/li&gt;
&lt;li&gt;фреймворк для аутентификации;&lt;/li&gt;
&lt;li&gt;компонент TreeTable;&lt;/li&gt;
&lt;li&gt;компонент сворачиваемая панель;&lt;/li&gt;
&lt;li&gt;компонент выбор даты;&lt;/li&gt;
&lt;li&gt;компонент совет дня.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Swing threading&lt;/b&gt;&lt;br /&gt;
&lt;code&gt;Swing&lt;/code&gt; рассчитан на то, что приложения на его базе будут запускаться не в основном(main) потоке, а в отдельном. И если сам &lt;code&gt;Swing&lt;/code&gt; может простить такую ошибку, то некоторые его компоненты - нет.&lt;br /&gt;
Java платформа предоставляет класс &lt;code&gt;SwingUtilities&lt;/code&gt;, который поможет вам запустить &lt;code&gt;Swing&lt;/code&gt;-приложение в отдельном потоке. Используйте метод &lt;code&gt;invokeLater()&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;DisableExplicitGC&lt;/b&gt;&lt;br /&gt;
Явный вызов сборщика мусора (&lt;code&gt;System.gc()&lt;/code&gt;) - плохая идея и типичный Java performance антипаттерн. Для игнорирования этих вызовов в HotSpot JVM можно использовать флаг &lt;code&gt;-XX:+DisableExplicitGC&lt;/code&gt;. Аналогичный флаг есть и для IBM JVM: &lt;code&gt;-Xdisableexplicitgc&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;HeapDumpOnOutOfMemoryError&lt;/b&gt;&lt;br /&gt;
Флаг &lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/code&gt; заставляет JVM при переполнении делать снапшот кучи для последующего анализа с помощьют утилиты &lt;code&gt;jhat&lt;/code&gt;. В IBM JVM эта возможность включена по умолчанию.&lt;br /&gt;
&lt;br /&gt;
Статья &lt;a href="http://www.ibm.com/developerworks/java/library/j-5things15/index.html"&gt;5 things you didn't know about ... multithreaded programming&lt;/a&gt; уже переведена &lt;a href="http://habrahabr.ru/blogs/java/108016/"&gt;на хабрахабре&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Также полезно ознакомиться, хотя бы поверхностно, со статьями про мониторинг производительности(&lt;a href="http://www.ibm.com/developerworks/java/library/j-5things7.html"&gt;раз&lt;/a&gt;, &lt;a href="http://www.ibm.com/developerworks/java/library/j-5things8.html"&gt;два&lt;/a&gt;) и &lt;a href="http://www.ibm.com/developerworks/java/library/j-5things11/index.html"&gt;про аргументы командной строки для JVM&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-6629386787840389110?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/VRKHaRnGe3A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/6629386787840389110/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/n-things-you-didnt-know-about-java.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6629386787840389110?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6629386787840389110?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/VRKHaRnGe3A/n-things-you-didnt-know-about-java.html" title="N things you didn't know about Java" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/n-things-you-didnt-know-about-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4BRHk5fyp7ImA9Wx9WEk0.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-7382525592090699859</id><published>2010-11-20T02:34:00.001+03:00</published><updated>2011-01-16T23:15:55.727+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-16T23:15:55.727+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="задротство" /><title>Интересный вопрос о Java</title><content type="html">Какое значение примет переменная &lt;code&gt;valueInQuestion&lt;/code&gt;?&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;{ int valueInQuestion = o(); }&lt;br /&gt;
private int o() {&lt;br /&gt;
try { return 1; } finally { return 2; }&lt;br /&gt;
}&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Ответ, как  всегда, кроется в JLS: &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.17"&gt;14.17 The return Statement&lt;/a&gt;, в последнем абзаце.&lt;br /&gt;
&lt;br /&gt;
За задачу спасибо Darth Beleg.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-7382525592090699859?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/OIZ0vzDwVkE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/7382525592090699859/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/java_20.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7382525592090699859?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/7382525592090699859?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/OIZ0vzDwVkE/java_20.html" title="Интересный вопрос о Java" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/java_20.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4HQXY6fyp7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-4503566337351056238</id><published>2010-11-17T00:01:00.003+03:00</published><updated>2011-01-19T21:48:50.817+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:48:50.817+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Enums and Annotations</title><content type="html">&lt;div style="text-align: justify;"&gt;&lt;br /&gt;
&lt;b&gt;Item 30. Используйте &lt;code&gt;enum&lt;/code&gt;-ы вместо целочисленных контант.&lt;/b&gt;&lt;br /&gt;
В Java 1.5 был введён новый тип - &lt;code&gt;enum&lt;/code&gt; (перечисление). Перечисление имеет фиксированный набор допустимых значений: это могут быть времена года, планеты солнечной системы, масти игральных карт и т. п. Основная идея &lt;code&gt;enum&lt;/code&gt;-ов: это классы, экпортирующие по одному экземпляру для каждого своего значения. &lt;code&gt;Enum&lt;/code&gt;-ы - это обобщение синглотонов.&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;code&gt;Enum&lt;/code&gt;-ы обеспечивают безопасность программы на этапе компиляции. Если вы объявляете параметр &lt;code&gt;enum&lt;/code&gt;-типа, то гарантируется, что значение, которое будет передано методу, будет одним из элементов этого &lt;code&gt;enum&lt;/code&gt;-а и не &lt;code&gt;null&lt;/code&gt;. Попытки передать значение неправильного типа, ровно как и использование &lt;code&gt;==&lt;/code&gt; для сравнения элементов различных &lt;code&gt;enum&lt;/code&gt;-ов, приведут к ошибкам на этапе компиляции программы.&lt;br /&gt;
В &lt;code&gt;enum&lt;/code&gt;-ы можно добавлять свои собственные методы, чтобы, например, ассоциировать некоторые данные с конкретными элементами. Можно имплементировать ими интерфейсы; в них уже имплементированы &lt;code&gt;Comparable&lt;/code&gt; и &lt;code&gt;Serializable&lt;/code&gt;. Есть готовые методы &lt;code&gt;ordinal()&lt;/code&gt;, &lt;code&gt;valueOf(String)&lt;/code&gt; и &lt;code&gt;toString()&lt;/code&gt;. Допустимо добавлять даже абстрактные методы, чтобы обеспечить каждый элемемент перечисления собственной реализацией.&lt;br /&gt;
Для ознакомления с другими, реже применяемыми особенностями &lt;code&gt;enum&lt;/code&gt;-ов рекомендуется прочитать параграф из книги целиком.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 31. Используйте поля-члены &lt;code&gt;enum&lt;/code&gt;-ов вместо их порядковых номеров.&lt;/b&gt;&lt;br /&gt;
Все &lt;code&gt;enum&lt;/code&gt;-ы имеют метод &lt;code&gt;ordinal()&lt;/code&gt;, возврающий порядковый номер элемента, но его использование почти всегда затрудняет поддержку и развитие кода. Вместо него лучше вводить собственные поля и работать с их значениями.&lt;br /&gt;
В спецификации метода &lt;code&gt;ordinal()&lt;/code&gt; написано: "Most programmers will have no use for this method. It is designed for use by general-purpose &lt;code&gt;enum&lt;/code&gt;-based data structures such as &lt;code&gt;EnumSet&lt;/code&gt; and &lt;code&gt;EnumMap&lt;/code&gt;." Если вы не пишите подобную структуру, то лучше всего обходить этот метод стороной.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 32. Используйте &lt;code&gt;EnumSet&lt;/code&gt; вместо битовых полей.&lt;/b&gt;&lt;br /&gt;
Если элементы перечисляемого типа используются в множествах (set), одним из способов реализации является набор констант-степеней двойки с последующим применением битовой арифметики к ним. Этот путь опасен и неудобен. Вместо него рекомендуется использовать уже готовую реализацию - &lt;code&gt;EnumSet&lt;/code&gt;. К слову, если количество элементов в &lt;code&gt;enum&lt;/code&gt;-е не более 64х, то в &lt;code&gt;EnumSet&lt;/code&gt;-е используется та же самая битовая арифметика, а данные о наборе лежат в одном long-е, что обеспечивает максимальную производительность структуры.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 33. Используйте &lt;code&gt;EnumMap&lt;/code&gt; вместо индексации номеров.&lt;/b&gt;&lt;br /&gt;
Аналогично предыдущему параграфу, только &lt;code&gt;Map&lt;/code&gt; вместо &lt;code&gt;Set&lt;/code&gt;. Имплементация Map, использующая элементы &lt;code&gt;enum&lt;/code&gt;-а в качестве ключей, уже готова - &lt;code&gt;EnumMap&lt;/code&gt;, и не нужно придумывать ничего своего. Внутри неё для хранения данных используется обычный массив, что обеспечивает хорошую производительность.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 34. Эмулируйте наследование от &lt;code&gt;enum&lt;/code&gt;-ов с помощью интерфейсов.&lt;/b&gt;&lt;br /&gt;
Наследование для &lt;code&gt;enum&lt;/code&gt;-ов запрещено не случайно. Но в некоторых случаях подобный механизм просто необходим (например, если речь идёт об опкодах, и нужно в клиентском коде уметь создавать свои). Для этого очень удобно объявить единый интерфейс, отделённый от перечисления, и имплементировать его &lt;code&gt;enum&lt;/code&gt;-ом.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 35. Предпочитайте аннотации вместо соглашений о наименованиях.&lt;/b&gt;&lt;br /&gt;
До релиза Java 1.5 в программах применялись соглашения о наименованиях, чтобы указать на особое трактование некоторых элементов кода. Например, &lt;code&gt;JUnit&lt;/code&gt; изначально требовал называть тестовые методы, начиная со слова &lt;code&gt;test&lt;/code&gt;. Такой подход имеет массу очевидных недостатков. Все эти проблемы были успешно решены в Java 1.5 с помощью аннотаций (annotations).&lt;br /&gt;
Параграф приводит несколько примеров создания своих аннотаций. Вывод таков, что аннотации - достаточно мощный и полезный инструмент, и теперь нет причин использовать соглашения о наименованиях.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 36. Нерпеменно используйте аннотацию &lt;code&gt;Override&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
Аннотацию &lt;code&gt;Override&lt;/code&gt; можно применять только к объявлениям методов. Она указывает на то, что объявление метода переопределяет его объявление в суперклассе. Повсеместное использование этой аннотации поможет избавиться от проблем, возникающих, когда допускается ошибка в объявлении метода, и вместо переопределения происходит его перегрузка (overloading, это когда два метода имеют одинаковые названия, но разные параметры). Современные среды разработки производят инспекции кода и предупреждают о возможности таких проблем.&lt;br /&gt;
Начиная с релиза 1.6, аннотацию &lt;code&gt;Override&lt;/code&gt; можно использовать не только в подклассах, но и в подинтерфейсах.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 37. Используйте интерфейсы-маркеры (marker interfaces) для определения типов.&lt;/b&gt;&lt;br /&gt;
Интерфейс-маркер не содержит методов и полей, а только помечает класс, который его имплементирует, как имеющий определённое свойство. Очевидный пример - интерфейс &lt;code&gt;Serializable&lt;/code&gt;.&lt;br /&gt;
Интерфейсы-маркеры имеют следующие преимущества перед маркирующими аннотациями (Item 35):&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Они определяют тип, что позволяет осуществлять проверку на этапе компиляции. Например, метод &lt;code&gt;ObjectOutputStream.write(Object)&lt;/code&gt; должен бы в качестве параметра принимать не &lt;code&gt;Object&lt;/code&gt;, а &lt;code&gt;Serializable&lt;/code&gt;. Но по необъяснимым причинам авторы класса этого не сделали.&lt;/li&gt;
&lt;li&gt;Интерфейсы могут наследоваться, что позволяет более точно осуществлять таргетинг. Примером здесь служит интерфейс &lt;code&gt;Set&lt;/code&gt;, наследующийся от &lt;code&gt;Collection&lt;/code&gt; и не добавляющий никаких методов. На самом деле &lt;code&gt;Set&lt;/code&gt; - не совсем интерфейс-маркер, так как он переопределяет контракты некоторых методов интерфейса &lt;code&gt;Collection&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;Преимущества аннотаций-маркеров перед интерфейсами:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;В аннотацию можно легко вложить со временем дополнительную информацию, что невозможно для интерфейса. Интерфейс вообще нельзя изменять после того, как его имплементировали.&lt;/li&gt;
&lt;li&gt;Аннотации можно применять не только к классам и интерфейсам, но и к другим программным элементам, таким, как члены или любые объявления. Поэтому именно их зачастую используют в различных фреймворках.&lt;/li&gt;
&lt;/ol&gt;В конечном итоге, аннотацию-маркер следует использовать, если её нужно применять не только к типам, но и к другим программным элементам, либо если маркер, возможно, будет эволюционировать. В остальных случаях, особенно если будут методы, принимающие только маркированные объекты, лучше применять интерфейс.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;P.S.&lt;/b&gt; На андроиде &lt;code&gt;enum&lt;/code&gt;-ы не очень хороши и рекомендуется их избегать. &lt;a href="http://developer.android.com/guide/practices/design/performance.html#avoid_enums"&gt;Читать&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-4503566337351056238?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/-6W8Otlbw_0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/4503566337351056238/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/effective-java-enums-and-annotations.html#comment-form" title="Комментарии: 1" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4503566337351056238?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4503566337351056238?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/-6W8Otlbw_0/effective-java-enums-and-annotations.html" title="Effective Java: Enums and Annotations" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/effective-java-enums-and-annotations.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkECQHs4fyp7ImA9Wx9RFk8.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-4975693075837492001</id><published>2010-11-12T23:36:00.002+03:00</published><updated>2010-12-18T01:24:21.537+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-18T01:24:21.537+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Про try-catch блоки Java</title><content type="html">Если выполнение блока try завершилось неудачно и выкинулся некоторый &lt;code&gt;Throwable&lt;/code&gt; T, то catch-блоки будут просматриваться сверху вниз в поисках подходящего. Подходящим является блок, обрабатывающий такой &lt;code&gt;Throwable&lt;/code&gt; V, что тип T можно привести к типу V.&lt;br /&gt;
&lt;br /&gt;
Это означает, что следующий код содержит недостижимый блок:&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
try {&lt;br /&gt;
// ...&lt;br /&gt;
} catch (Exception e) {&lt;br /&gt;
// ...&lt;br /&gt;
} catch (NullPointerException e) {&lt;br /&gt;
// ...&lt;br /&gt;
}&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
В более общем случае нельзя располагать один catch-блок выше другого, если первый ловит Throwable-суперкласс второго.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-4975693075837492001?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/xJNuoyd2UyQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/4975693075837492001/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/try-catch.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4975693075837492001?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/4975693075837492001?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/xJNuoyd2UyQ/try-catch.html" title="Про try-catch блоки Java" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/try-catch.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEDSXY6fCp7ImA9Wx5aEUg.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-2516074795861601435</id><published>2010-11-07T22:04:00.000+03:00</published><updated>2010-11-07T22:04:38.814+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-07T22:04:38.814+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Иерархия пакетов в Java</title><content type="html">&lt;div style="text-align: justify;"&gt;Иерархии пакетов в языке Java нет. Конечно, "про себя" мы можем думать, что пакет &lt;code&gt;java.util.regex&lt;/code&gt; лежит внутри пакета &lt;code&gt;java.util&lt;/code&gt;, но для компилятора это просто два разных пакета.&lt;br /&gt;
&lt;br /&gt;
Так, классы &lt;code&gt;codingbreak.test.ClassInTest&lt;/code&gt; и &lt;code&gt;codingbreak.test.sub.ClassInSub&lt;/code&gt; не имеют доступа к пакето-приватным(package-private) полям и методам друг друга.&lt;br /&gt;
&lt;br /&gt;
Кроме того, например, импорт &lt;code&gt;java.util.*&lt;/code&gt; не покрывает импорта &lt;code&gt;java.util.regex.Pattern&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-2516074795861601435?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/zM-EpmQE2LA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/2516074795861601435/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/java.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2516074795861601435?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/2516074795861601435?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/zM-EpmQE2LA/java.html" title="Иерархия пакетов в Java" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8BQ3w-eyp7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-3821060112395344110</id><published>2010-11-07T21:48:00.001+03:00</published><updated>2011-01-19T21:47:32.253+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:47:32.253+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Generics</title><content type="html">&lt;div style="text-align: justify;"&gt;Переходим к следующей главе книги. О том, что это за серия постов и зачем, можно прочитать в &lt;a href="http://codingbreak.blogspot.com/2010/09/effective-java.html"&gt;первом сообщении серии&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 23. Не используйте raw классы в новом коде.&lt;/b&gt;&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Generic-и были добавлены в Java 1.5, чтобы сделать программы более безопасными и читаемыми. Поддержка raw-типов сохранилась &lt;u&gt;только&lt;/u&gt; для обратной совместимости программ. При написании нового кода не стоит их использовать, так как это небезопасно.&lt;br /&gt;
Иногда воспользоваться generic-ами не представляется возможным, например, когда неизвестно, что будет лежать в передаваемой коллекции. Для этого случая в языке предусмотрены bounded и unbounded wildcard types.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 24. Не игнорируйте предупреждения компилятора об опасном преобразовании типов.&lt;/b&gt;&lt;br /&gt;
Чтобы написать по-настоящему безопасный код, который не будет порождать ошибки времени выполнения, нужно рассматривать каждое такое предупреждение компилятора.&lt;br /&gt;
Если избавиться от предупреждения по каким-либо причинами невозможно, но сам код точно безопасный, тогда (и только тогда) следует использовать аннотацию &lt;code&gt;@SuppressWarnings("unchecked")&lt;/code&gt;, причём применять её нужно всегда на как можно меньший кусок кода. Рекомендуется к каждому использованию этой аннотации добавлять комментарий, объясняющий, почему код безопасен.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 25. Используйте списки (lists) вместо массивов.&lt;/b&gt;&lt;br /&gt;
Отмечается два важных отличия массивов и типизированных контейнеров.&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Массивы - ковариантны, Generic-и - инвариантны. Это значит, что если Sub - подкласс класса Super, то Sub[] - подкласс Super[], что неверно для типизированных классов. Это делает использование типизированных контейнеров более безопасным, чем использование массивов (хотя на первый взгляд кажется, что это только доставляет неудобства).&lt;/li&gt;
&lt;li&gt;Проверка типов для массивов происходит во время выполнения программы, а использование Generic-ов накладывает ограничения только на этапе компиляции, в рантайме же эта информация о типизации совершенно не используется (вернее сказать, её к этому времени просто уже нет).&lt;/li&gt;
&lt;/ol&gt;В связи с этими фундаментальными различиями массивы и типизированные классы довольно плохо комбинируются. В большинстве случаев нужно вместо массивов использовать типизированные списки, жертвуя тем самым некоторой производительностью в пользу безопасности.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 26. Предпочитайте типизированные классы (generic types).&lt;/b&gt;&lt;br /&gt;
Generic-и - это хорошо, и если можно добавить их к классу, то нужно это сделать. В параграфе описывается процесс изменения класса для его типизации.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 27. Предпочитайте типизированные методы (generic methods).&lt;/b&gt;&lt;br /&gt;
Аналогично предыдущему параграфу. Отмечается удобство использования типизированных фабричных методов:&lt;br /&gt;
Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; anagrams = newHashMap();&lt;br /&gt;
вместо&lt;br /&gt;
Map&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt; anagrams = new HashMap&amp;lt;String, List&amp;lt;String&amp;gt;&amp;gt;();&lt;br /&gt;
Generic-и могут быть рекурсивными.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 28. Используйте bounded wildcards для улучшения своего API.&lt;/b&gt;&lt;br /&gt;
Как было сказано выше, generic-и инвариантны, т.е. List&amp;lt;String&amp;gt; не является подклассом List&amp;lt;Object&amp;gt;. Иногда это доставляет серьёзные неудобства, но есть выход - bounded wildcards. Они бывают двух видов - "extends" и "super", каждый из которых покрывает, соответственно, все подклассы и все суперклассы указанного типа. Для того, чтобы быстро соображать, какой их них следует использовать, можно пользоваться т.н. правилом PECS: "PECS stands for producer-extends, consumer-super."&lt;br /&gt;
Не рекомендуется использовать wildcard-типы в качестве возвращаемых типов.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 29. Про безопасные гетерогенные контейнеры.&lt;/b&gt;&lt;br /&gt;
Типичное применение generic-ов (как в Collections API) ограничивает нас фиксированным числом типовых параметров контейнера. Это ограничение можно обойти, если типизировать не контейнер целиком, а только его ключ. В данном параграфе приводится пример написания такого безопасного контейнера, а также отмечаются некоторые особенности класса Class&amp;lt;T&amp;gt; как параметризированного типа.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-3821060112395344110?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/4LOR8rKg_Ms" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/3821060112395344110/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/11/effective-java-generics.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/3821060112395344110?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/3821060112395344110?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/4LOR8rKg_Ms/effective-java-generics.html" title="Effective Java: Generics" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/11/effective-java-generics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8EQHk7eip7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-6720318441032733768</id><published>2010-10-13T00:32:00.002+04:00</published><updated>2011-01-19T21:46:41.702+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:46:41.702+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Классы и интерфейсы</title><content type="html">&lt;div style="text-align: justify;"&gt;Продолжение серии постов об основных идеях книги Effective Java (2-е издание).&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;Item 13. Минимизируйте доступность классов и их членов.&lt;/b&gt;&lt;br /&gt;
Известное правило: каждый класс, метод или поле класса нужно делать настолько недоступными, насколько это возможно. Другими словами, необходимо минимизировать открытость вашей программы до тех пор, пока это возможно для использования её по назначению.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 14. В открытых (public) классах всегда используйте гетеры и сетеры (getters and setters) вместо открытых полей.&lt;/b&gt;&lt;br /&gt;
Открытые классы никогда не должны обеспечивать прямой доступ к своим полям, чтобы не позволить нарушить целостность данных. В меньшей степени это относится к неизменяемым (immutable) полям, однако, прежде, чем открыть доступ к такому полю, следует помнить, что публичный API класса нельзя будет изменить в будущем.&lt;br /&gt;
Если класс приватный (private) или пакето-приватный (package-private), то допустимо применение прямого доступа к полям.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 15. Старайтесь писать неизменяемые (immutable) классы.&lt;/b&gt;&lt;br /&gt;
Этому есть несколько причин:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;неизменяемые классы просты для понимания и применения;&lt;/li&gt;
&lt;li&gt;они не требуют синхронизации многопоточного доступа;&lt;/li&gt;
&lt;li&gt;их компоненты также неизменяемы, их можно использовать и в других экземплярах класса, избегая копирования;&lt;/li&gt;
&lt;li&gt;облегчают поддержание инвариантов других, более сложных объектов.&lt;/li&gt;
&lt;/ul&gt;Единственный недостаток у неизменяемых классов - это то, что для каждого значения нужен новый объект, что увеличивает используемый объём памяти.&lt;br /&gt;
В начале параграфа приводится необходимое и достаточное условие того, чтобы класс был неизменяемым.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 16. Предпочитайте композицию вместо наследования.&lt;/b&gt;&lt;br /&gt;
Наследование - мощный инструмент, но, будучи применённым неправильно, может сделать программу уязвимой. Наследование вполне допустимо, если суперкласс и наследники находятся под контролем одних и тех же программистов. В ином случае возникает опасность.&lt;br /&gt;
Наследование нарушает инкапсуляцию. Чтобы правильно отнаследоваться от класса, нужно знать, как он работает. Таким образом, если изменится суперкласс, его подклассы могут перестать функционировать. Поэтому каждый класс должен быть либо спроектирован для наследования от него клиентским кодом, либо такое наследование должно быть запрещено.&lt;br /&gt;
Зачастую, можно отказаться от наследования, заменив его композицией, то есть вместо подкласса написав т.н. класс-обёртку (wrapper).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 17. Проектируйте и документируйте возможность наследования от класса, либо запрещайте это наследование.&lt;/b&gt;&lt;br /&gt;
Если предполагается, что от класса будут наследоваться, то нужно документировать не только то, &lt;i&gt;что&lt;/i&gt; перегружаемые методы делают, но и то, &lt;i&gt;как&lt;/i&gt; они это делают. Безусловно, это нарушает инкапсуляцию.&lt;br /&gt;
Кроме того, необходимо открыть доступ к некоторым внутренностям такого класса с помощью модификатора protected.&lt;br /&gt;
Есть ещё один важный момент: ни конструктор, ни методы clone, readObject не должны вызывать перегружаемые методы, прямо или косвенно. В книге приводится хороший пример, демонстрирующий это.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 18. Предпочитайте интерфейсы абстрактным классам.&lt;/b&gt;&lt;br /&gt;
Поскольку Java не поддерживает множественное наследование, применение абстрактных классов сильно ограничено по сравнению с интерфейсами. Вообще, у интерфейсов много преимуществ по сравнению с абстрактными классами, достаточно очевидных, но есть и недостаток: внести изменения в уже существующий, широко применяемый интерфейс практически невозможно.&lt;br /&gt;
Стоит заметить возможность комбинирования преимуществ абстрактных классов и интефейсов путём введения т.н. skeletal implementation. Наиболее известные примеры этого - AbstractCollection, AbstractMap, AbstractSet и AbstractList.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 19. Используйте интерфейсы только для определения типов.&lt;/b&gt;&lt;br /&gt;
Другими словами, не нужно их использовать не по назначению, например, для хранения значений констант.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 20. Предпочитайте иерархии классов вместо tagged классов.&lt;/b&gt;&lt;br /&gt;
Под tagged классом имеется в виду такой класс, который содержит некоторое поле-тег, определяющее его поведение. Приведён пример такой реализации класса Shape, в котором есть поле shape, определяющее конкретную форму объекта. Такой подход имеет ряд недостатков и не имеет значительных преимуществ. Вместо этого рекомендуется строить иерархию классов. В данном случае следовало бы организовать абстрактный класс Figure, в котором объявляются основные методы, и классы-наследники, каждый из которых представляет конкретную фигуру.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 21. Используйте объекты-функции (function objects) для представления стратегий (strategies).&lt;/b&gt;&lt;br /&gt;
&lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Шаблон проектирования Стратегия&lt;/a&gt; стоит использовать, когда необходимо определить поведение некоторой функции путём передачи ей другой функции. Ярким примером использования этого шаблона в Java является интерфейс Comparator.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 22. Предпочитайте статические внутренние классы вместо нестатических.&lt;/b&gt;&lt;br /&gt;
Есть 4 типа внутренних классов: статические, нестатические, анонимные и локальные. Каждый из этих типов имеет своё применение, о чём и рассказано в параграфе.&lt;br /&gt;
Хотелось бы отметить следующее: синтаксически разница между статическими и нестатическими внутренними классами очень мала - первый объявлен с модификатором static, второй - нет. Однако, на деле эти два типа имеют значительные различия. Общее правило для выбора между ними таково: если внутренний класс не требует доступа к содержащему его экземпляру, то следует использовать статический класс.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-6720318441032733768?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/xNXhUYpHCno" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/6720318441032733768/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/10/effective-java.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6720318441032733768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/6720318441032733768?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/xNXhUYpHCno/effective-java.html" title="Effective Java: Классы и интерфейсы" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/10/effective-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAHR3cyfSp7ImA9Wx9WFEs.&quot;"><id>tag:blogger.com,1999:blog-7470289436282357198.post-1924026672678494472</id><published>2010-09-29T19:04:00.004+04:00</published><updated>2011-01-19T21:45:36.995+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-19T21:45:36.995+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="effective java" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><title>Effective Java: Общие для всех объектов методы</title><content type="html">&lt;div style="text-align: justify;"&gt;Следующая глава книги.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 8. Соблюдайте контракт метода &lt;code&gt;equals&lt;/code&gt;, переопределяя его.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Случаи, когда переопределять метод &lt;code&gt;equals&lt;/code&gt; не требуется:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;каждый экземпляр класса по определению уникален;&lt;/li&gt;
&lt;li&gt;нет необходимости сравнивать экземпляры "логически";&lt;/li&gt;
&lt;li&gt;суперкласс переопределил этот метод, и его поведение подходит и для данного подкласса;&lt;/li&gt;
&lt;li&gt;класс приватный или package-private и вы уверены, что метод &lt;code&gt;equals&lt;/code&gt; не используется.&lt;/li&gt;
&lt;/ul&gt;Метод &lt;code&gt;equals&lt;/code&gt; необходимо переопределять, если могут существовать различные экземпляры класса, логически эквивалентные друг другу.&lt;br /&gt;
В конце параграфа приводится рецепт хорошей реализации метода и следующие советы:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;всегда следует переопределять метод &lt;code&gt;hashCode&lt;/code&gt; при переопределении &lt;code&gt;equals&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;не надо увлекаться: к примеру, класс &lt;code&gt;File&lt;/code&gt; не углубляется до проверки, указывают ли различные символические ссылки на один и тот же файл;&lt;/li&gt;
&lt;li&gt;объявление метода &lt;code&gt;equals&lt;/code&gt; стоит писать очень внимательно, в противном случае вместо override можно сделать overload и ошибку будет довольно сложно найти.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Item 9. Всегда переопределяйте метод &lt;code&gt;hashCode&lt;/code&gt; при переопределении &lt;code&gt;equals&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Эквивалентные объекты должны иметь одиннаковый хэш-код. Несоблюдение этого правила приведёт к нарушению работы, как минимум, некоторых коллекций.&lt;br /&gt;
В параграфе приводится ряд рекомендаций по написанию удачной хэш-функции.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 10. Всегда переопределяйте метод &lt;code&gt;toString&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Это добавляет удобства при использовании класса, так как строка &lt;code&gt;(707) 867-5309&lt;/code&gt; говорит гораздо больше, чем &lt;code&gt;PhoneNumber@163b91&lt;/code&gt;.&lt;br /&gt;
Формат возвращаемой строки может быть как описан, так и не описан в документации класса. Естественно, будучи объявленным в документации, формат не сможет быть изменён в дальнейшем. В любом случае следует обеспечивать программный доступ к полям, используемым в &lt;code&gt;toString&lt;/code&gt;, чтобы не провоцировать клиентский код парсить строку, возвращаемую последним.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Item 11. Переопределяйте метод &lt;code&gt;clone&lt;/code&gt; с умом.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Этот параграф содержит слишком много пунктов, которые следовало бы написать сюда, поэтому я этого делать не буду. Если нужно спроектировать объект с возможностью клонирования, придётся перечитать параграф целиком. Однако, отдельно хотелось бы отметить следующие факты:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;При переопределении метода &lt;code&gt;clone&lt;/code&gt; в non-final классе всегда следует возвращать объект, полученный вызовом &lt;code&gt;super.clone&lt;/code&gt;, только тогда он будет иметь правильный тип.&lt;/li&gt;
&lt;li&gt;Если класс содержит ссылки на изменяемые (mutable) объекты, то при клонировании эти объекты должны быть рекурсивно склонированы вместо простого копирования ссылок на них, которое происходит по умолчанию. Общее правило таково, что клон и оригинал не должны иметь общих внутренностей, кроме неизменяемых (immutable).&lt;/li&gt;
&lt;li&gt;Иногда можно обойтись копирующим конструктором, это гораздо проще.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Item 12. Подумайте об имплементации интерфейса &lt;code&gt;Comparable&lt;/code&gt;.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Если для объектов рассматриваемого класса существует некоторый естесственный порядок (natural order), имеет смысл имплементировать этот интерфейс. Небольшие усилия, затраченные на создание функции сравнения, открывают для класса всю мощь стандартных алгоритмов и коллекций, требующих существование этого порядка. Обычно этот интерфейс имплементируют классы, представляющие какое-либо значение: число, дату и время и т.д.&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7470289436282357198-1924026672678494472?l=codingbreak.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingBreak/~4/I02nqakQdWI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://codingbreak.blogspot.com/feeds/1924026672678494472/comments/default" title="Комментарии к сообщению" /><link rel="replies" type="text/html" href="http://codingbreak.blogspot.com/2010/09/effective-java_29.html#comment-form" title="Комментарии: 0" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1924026672678494472?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7470289436282357198/posts/default/1924026672678494472?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CodingBreak/~3/I02nqakQdWI/effective-java_29.html" title="Effective Java: Общие для всех объектов методы" /><author><name>Сергей</name><uri>http://www.blogger.com/profile/06072560179480119743</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://codingbreak.blogspot.com/2010/09/effective-java_29.html</feedburner:origLink></entry></feed>

