Примечание . Я работаю над второй версией этого руководства, и мне нужна ваша помощь! Пожалуйста, используйте эту форму, чтобы оставить отзыв о том, что, по вашему мнению, должно быть в следующей версии. Спасибо!
Java — один из самых популярных языков программирования, но, похоже, никто не любит его использовать. Что ж, Java на самом деле является неплохим языком программирования, и, поскольку недавно вышла Java 8, я решил составить список библиотек, практик и инструментов, которые помогут улучшить использование Java. «Лучше» субъективно, поэтому я бы рекомендовал взять те части, которые вам интересны, и использовать их, а не пытаться использовать все сразу. Не стесняйтесь отправлять запросы на включение с предложениями дополнений.
Эта статья изначально была опубликована в моем блоге.
Читайте это на других языках: английский, 简体中文
Традиционно Java программировался в очень многословном стиле корпоративного JavaBean. Новый стиль намного чище, правильнее и приятнее для глаз.
Одна из самых простых вещей, которые мы, программисты, делаем — передаем данные. Традиционный способ сделать это — определить JavaBean:
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
Это многословно и расточительно. Даже если ваша IDE автоматически сгенерировала этот код, это пустая трата времени. Так что не делайте этого.
Вместо этого я предпочитаю структурный стиль C для написания классов, которые просто содержат данные:
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
Это сокращение количества строк кода вдвое. Кроме того, этот класс является неизменяемым, пока вы его не расширите, поэтому нам будет проще рассуждать о нем, поскольку мы знаем, что его нельзя изменить.
Если вы храните такие объекты, как Map или List, которые можно легко изменить, вместо этого вам следует использовать ImmutableMap или ImmutableList, которые обсуждаются в разделе, посвященном неизменяемости.
Если у вас довольно сложный объект, для которого вы хотите построить структуру, рассмотрите шаблон Builder.
Вы создаете статический внутренний класс, который будет создавать ваш объект. Он использует изменяемое состояние, но как только вы вызываете build, он создает неизменяемый объект.
Представьте, что у нас есть более сложный DataHolder . Конструктор для него может выглядеть так:
public class ComplicatedDataHolder {
public final String data ;
public final int num ;
// lots more fields and a constructor
public static class Builder {
private String data ;
private int num ;
public Builder data ( String data ) {
this . data = data ;
return this ;
}
public Builder num ( int num ) {
this . num = num ;
return this ;
}
public ComplicatedDataHolder build () {
return new ComplicatedDataHolder ( data , num ); // etc
}
}
}
Затем, чтобы использовать его:
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
В других местах есть лучшие примеры Строителей, но это должно дать вам представление о том, что это такое. В конечном итоге это приводит к большому количеству шаблонов, которых мы пытались избежать, но дает вам неизменяемые объекты и очень гибкий интерфейс.
Вместо того, чтобы создавать объекты-построители вручную, рассмотрите возможность использования одной из многих библиотек, которые помогут вам создавать построители.
Если вы создаете много неизменяемых объектов вручную, рассмотрите возможность использования обработчика аннотаций для автоматического создания их из интерфейсов. Это сводит к минимуму шаблонный код, снижает вероятность ошибок и способствует неизменности. В этой презентации представлено интересное обсуждение некоторых проблем, связанных с обычными шаблонами кодирования Java.
Некоторые замечательные библиотеки генерации кода являются неизменяемыми, например, Google auto-value и Lombok.
Проверенные исключения следует использовать с осторожностью, если вообще использовать. Они заставляют ваших пользователей добавлять множество блоков try/catch и оборачивать ваши исключения в свои собственные. Лучше вместо этого сделать так, чтобы ваши исключения расширяли RuntimeException. Это позволяет вашим пользователям обрабатывать ваши исключения так, как они хотят, вместо того, чтобы заставлять их обрабатывать/объявлять, что они выдаются каждый раз, что загрязняет код.
Один изящный трюк — поместить RuntimeExceptions в объявление throws вашего метода. Это не повлияет на компилятор, но через документацию сообщит вашим пользователям, что эти исключения могут быть созданы.
Это скорее раздел разработки программного обеспечения, чем раздел Java, но один из лучших способов написания тестируемого программного обеспечения — это использование внедрения зависимостей (DI). Поскольку Java настоятельно рекомендует объектно-ориентированный дизайн, для создания тестируемого программного обеспечения необходимо использовать внедрение зависимостей.
В Java это обычно делается с помощью Spring Framework. Он имеет либо соединение на основе кода, либо соединение на основе конфигурации XML. Если вы используете конфигурацию XML, важно не злоупотреблять Spring из-за его формата конфигурации на основе XML. В XML не должно быть абсолютно никакой логики или управляющих структур. Он должен только вводить зависимости.
Хорошей альтернативой использованию Spring является библиотека Google и Square Dagger или Google Guice. Они не используют формат файла конфигурации Spring XML, а вместо этого помещают логику внедрения в аннотации и код.
По возможности старайтесь избегать использования нулей. Не возвращайте пустые коллекции, если вместо этого вы должны были вернуть пустую коллекцию. Если вы собираетесь использовать значение null, рассмотрите аннотацию @Nullable. IntelliJ IDEA имеет встроенную поддержку аннотации @Nullable.
Подробнее о том, почему не использовать нули, читайте в статье «Худшая ошибка информатики».
Если вы используете Java 8, вы можете использовать отличный новый тип «Дополнительно». Если значение может присутствовать или отсутствовать, оберните его в необязательный класс следующим образом:
public class FooWidget {
private final String data ;
private final Optional < Bar > bar ;
public FooWidget ( String data ) {
this ( data , Optional . empty ());
}
public FooWidget ( String data , Optional < Bar > bar ) {
this . data = data ;
this . bar = bar ;
}
public Optional < Bar > getBar () {
return bar ;
}
}
Итак, теперь ясно, что данные никогда не будут нулевыми, но полоса может присутствовать, а может и отсутствовать. Необязательный имеет такие методы, как isPresent , из-за которых может показаться, что мало что отличается от простой проверки null . Но это позволяет вам писать такие утверждения, как:
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
Это намного лучше, чем прикованное, если проверяется значение null. Единственным недостатком использования Необязательного является то, что стандартная библиотека не имеет хорошей поддержки Необязательного, поэтому там по-прежнему требуется обработка значений NULL.
Если у вас нет веской причины сделать это иначе, переменные, классы и коллекции должны быть неизменяемыми.
Переменные можно сделать неизменяемыми с помощью Final :
final FooWidget fooWidget ;
if ( condition ()) {
fooWidget = getWidget ();
} else {
try {
fooWidget = cachedFooWidget . get ();
} catch ( CachingException e ) {
log . error ( "Couldn't get cached value" , e );
throw e ;
}
}
// fooWidget is guaranteed to be set here
Теперь вы можете быть уверены, что fooWidget не будет случайно переназначен. Ключевое слово Final работает с блоками if/else и с блоками try/catch. Конечно, если сам fooWidget не является неизменяемым, вы можете легко изменить его.
Коллекции должны, когда это возможно, использовать классы Guava ImmutableMap, ImmutableList или ImmutableSet. У них есть построители, поэтому вы можете создавать их динамически, а затем помечать их как неизменяемые, вызывая метод сборки.
Классы следует сделать неизменяемыми, объявив поля неизменяемыми (через Final ) и используя неизменяемые коллекции. При желании вы можете сделать сам класс финальным , чтобы его нельзя было расширить и сделать изменяемым.
Будьте осторожны, если вы обнаружите, что добавляете в класс Util много методов.
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
Эти классы на первый взгляд кажутся привлекательными, потому что методы, входящие в них, на самом деле не принадлежат какому-то одному месту. Итак, вы бросаете их все сюда во имя повторного использования кода.
Лекарство хуже болезни. Поместите эти классы туда, где они должны быть, и проводите агрессивный рефакторинг. Не называйте классы, пакеты или библиотеки слишком общими именами, например «MiscUtils» или «ExtrasLibrary». Это поощряет сброс туда несвязанного кода.
Форматирование гораздо менее важно, чем это представляет большинство программистов. Показывает ли последовательность, что вы заботитесь о своем ремесле, и помогает ли это другим читать? Абсолютно. Но давайте не будем тратить день на добавление пробелов в блоки if, чтобы они «совпадали».
Если вам абсолютно необходимо руководство по форматированию кода, я настоятельно рекомендую руководство по стилю Java от Google. Лучшая часть этого руководства — раздел «Практика программирования». Определенно стоит прочитать.
Документирование кода, ориентированного на пользователя, важно. А это означает использование примеров и разумных описаний переменных, методов и классов.
Следствием этого является недокументирование того, что не требует документирования. Если вам нечего сказать о том, что такое аргумент, или если он очевиден, не документируйте его. Шаблонная документация хуже, чем отсутствие документации вообще, поскольку она заставляет пользователей думать, что документация существует.
Java 8 имеет хороший синтаксис потоков и лямбда-выражений. Вы можете написать такой код:
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
Вместо этого:
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
Это позволяет вам писать более плавный и более читаемый код.
Правильное развертывание Java может быть немного сложным. В настоящее время существует два основных способа развертывания Java: использовать фреймворк или использовать более гибкое собственное решение.
Поскольку развертывание Java — непростая задача, были созданы платформы, которые могут помочь. Двумя лучшими являются Dropwizard и Spring Boot. Платформу Play также можно считать одной из таких платформ развертывания.
Все они пытаются снизить барьер на пути распространения вашего кода. Они особенно полезны, если вы новичок в Java или вам нужно сделать все быстро. Развертывание одного JAR проще, чем сложное развертывание WAR или EAR.
Однако они могут быть несколько негибкими и довольно самоуверенными, поэтому, если ваш проект не соответствует выбору, сделанному разработчиками вашей платформы, вам придется перейти к более ручной конфигурации.
Хорошая альтернатива : Gradle.
Maven по-прежнему остается стандартным инструментом для создания, упаковки и запуска тестов. Существуют альтернативы, такие как Gradle, но они не имеют такого же распространения, как Maven. Если вы новичок в Maven, вам следует начать с Maven by example.
Мне нравится иметь корневой POM со всеми внешними зависимостями, которые вы хотите использовать. Это будет выглядеть примерно так. Этот корневой POM имеет только одну внешнюю зависимость, но если ваш продукт достаточно велик, у вас их будут десятки. Ваш корневой POM должен быть отдельным проектом: находиться под контролем версий и выпускаться, как и любой другой проект Java.
Если вы считаете, что пометка корневого POM для каждого изменения внешних зависимостей — это слишком много, вы не тратите неделю на отслеживание ошибок межпроектных зависимостей.
Все ваши проекты Maven будут включать ваш корневой POM и всю информацию о его версии. Таким образом, вы получаете выбранную вашей компанией версию каждой внешней зависимости и все правильные плагины Maven. Если вам нужно подключить внешние зависимости, это работает следующим образом:
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
Если вам нужны внутренние зависимости, ими должен управлять каждый отдельный проект. раздел. В противном случае было бы трудно сохранить правильный номер корневой версии POM.
Одна из лучших особенностей Java — это огромное количество сторонних библиотек, которые делают все. По сути, каждый API или набор инструментов имеет Java SDK, и его легко подключить с помощью Maven.
И сами эти библиотеки Java зависят от конкретных версий других библиотек. Если вы подключите достаточное количество библиотек, вы получите конфликты версий, то есть что-то вроде этого:
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
Какая версия будет включена в ваш проект?
С плагином конвергенции зависимостей Maven сборка будет ошибочной, если ваши зависимости не используют одну и ту же версию. Тогда у вас есть два варианта решения конфликта:
Выбор того, что выбрать, зависит от вашей ситуации: если вы хотите отслеживать версию одного проекта, то исключение имеет смысл. С другой стороны, если вы хотите указать это явно, вы можете выбрать версию, хотя вам придется обновлять ее при обновлении других зависимостей.
Очевидно, вам нужен какой-то сервер непрерывной интеграции, который будет непрерывно создавать ваши версии SNAPSHOT и теги на основе тегов git.
Дженкинс и Трэвис-Си — естественный выбор.
Покрытие кода полезно, и у Cobertura есть хороший плагин Maven и поддержка CI. Существуют и другие инструменты покрытия кода для Java, но я использовал Cobertura.
Вам нужно место для размещения созданных вами JAR-файлов, WAR-файлов и EAR-файлов, поэтому вам понадобится репозиторий.
Распространенный выбор — Artifactory и Nexus. Оба работают и имеют свои плюсы и минусы.
У вас должна быть собственная установка Artifactory/Nexus и зеркально отражать на ней свои зависимости. Это предотвратит сбой вашей сборки из-за выхода из строя какого-либо вышестоящего репозитория Maven.
Итак, теперь у вас есть скомпилированный код, настроенный репозиторий, и вам нужно разместить свой код в среде разработки и, в конечном итоге, отправить его в производство. Не экономьте здесь, потому что автоматизация будет приносить дивиденды в течение длительного времени.
Типичным выбором являются Chef, Puppet и Ansible. Я написал альтернативу под названием Squadron, которую, я, конечно, думаю, вам стоит попробовать, потому что ее легче сделать правильно, чем альтернативы.
Независимо от того, какой инструмент вы выберете, не забудьте автоматизировать развертывание.
Вероятно, лучшая особенность Java — это огромное количество имеющихся в ней библиотек. Это небольшая коллекция библиотек, которая, вероятно, будет применима к самой большой группе людей.
Стандартная библиотека Java, которая когда-то была удивительным шагом вперед, теперь выглядит так, будто в ней отсутствуют несколько ключевых функций.
Проект Apache Commons имеет множество полезных библиотек.
Кодек Commons имеет множество полезных методов кодирования/декодирования для строк Base64 и шестнадцатеричных строк. Не тратьте время на их переписывание.
Commons Lang — это библиотека для манипулирования и создания строк, наборов символов и множества различных служебных методов.
В Commons IO есть все методы, связанные с файлами, которые вам могут понадобиться. Он имеет FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines и многое другое.
Guava — отличная библиотека Google «вот чего не хватает в Java». Почти сложно выделить все, что мне нравится в этой библиотеке, но я попробую.
Кэш — это простой способ получить кэш в памяти, который можно использовать для кэширования доступа к сети, доступа к диску, функций запоминания или чего-то еще. Просто реализуйте CacheBuilder, который сообщит Guava, как создать кеш, и все готово!
Неизменяемые коллекции. Их много: ImmutableMap, ImmutableList или даже ImmutableSortedMultiSet, если вам так нравится.
Мне также нравится писать изменяемые коллекции в стиле Guava:
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
Существуют статические классы для списков, карт, наборов и многого другого. Они чище и легче читаются.
Если вы застряли на Java 6 или 7, вы можете использовать класс Collections2, в котором есть такие методы, как фильтр и преобразование. Они позволяют вам писать свободный код без поддержки потоков Java 8.
В Guava тоже есть простые вещи, такие как Joiner , который объединяет строки по разделителям, и класс для обработки прерываний, игнорируя их.
Библиотека Google Gson — это простая и быстрая библиотека анализа JSON. Это работает следующим образом:
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
Работать с ним действительно легко и приятно. В руководстве пользователя Gson есть еще много примеров.
Одно из моих постоянных неудобств в Java заключается в том, что в стандартной библиотеке нет встроенных кортежей. К счастью, проект кортежей Java это исправляет.
Он прост в использовании и отлично работает:
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang — это функциональная библиотека, предназначенная для добавления недостающих функций, которые должны были быть частью Java 8. Некоторые из этих функций
Существует несколько библиотек Java, которые зависят от исходных коллекций Java. Они ограничены тем, чтобы оставаться совместимыми с классами, которые были созданы с объектно-ориентированной направленностью и предназначены для изменения. Коллекции Javaslang для Java — это совершенно новый подход, вдохновленный Haskell, Clojure и Scala. Они созданы с функциональной направленностью и имеют неизменный дизайн.
Подобный код автоматически становится потокобезопасным и не требует try-catch:
// Success/Failure containing the result/exception
public static Try < User > getUser ( int userId ) {
return Try . of (() -> DB . findUser ( userId ))
. recover ( x -> Match . of ( x )
. whenType ( RemoteException . class ). then ( e -> ...)
. whenType ( SQLException . class ). then ( e -> ...));
}
// Thread-safe, reusable collections
public static List < String > sayByeBye () {
return List . of ( "bye, " bye ", "collect" , "mania" )
. map ( String :: toUpperCase )
. intersperse ( " " );
}
Joda-Time — лучшая библиотека времени, которую я когда-либо использовал. Просто, понятно, легко проверить. Что еще можно попросить?
Вам это понадобится только в том случае, если вы еще не используете Java 8, поскольку у нее есть собственная новая библиотека времени, которая не отстой.
Ломбок — интересная библиотека. С помощью аннотаций это позволяет уменьшить шаблонность, от которой так сильно страдает Java.
Хотите использовать сеттеры и геттеры для переменных вашего класса? Простой:
public class Foo {
@ Getter @ Setter private int var ;
}
Теперь вы можете сделать это:
final Foo foo = new Foo ();
foo . setVar ( 5 );
И это намного больше. Я еще не использовал Lombok в производстве, но не могу дождаться.
Хорошие альтернативы : Джерси или Спарк.
Есть два основных лагеря для создания веб-сервисов RESTful на Java: JAX-RS и все остальное.
JAX-RS — традиционный способ. Вы объединяете аннотации с интерфейсами и реализациями для формирования веб-сервиса, используя что-то вроде Джерси. Что хорошо в этом, так это то, что вы можете легко создавать клиентов только из класса интерфейса.
Платформа Play представляет собой радикально иной подход к веб-сервисам в JVM: у вас есть файл маршрутов, а затем вы пишете классы, на которые ссылаются эти маршруты. На самом деле это целая платформа MVC, но вы можете легко использовать ее только для веб-сервисов REST.
Он доступен как для Java, так и для Scala. Он немного страдает от того, что изначально ориентирован на Scala, но его по-прежнему удобно использовать в Java.
Если вы привыкли к микрофреймворкам, таким как Flask в Python, Spark будет вам очень знаком. Особенно хорошо он работает с Java 8.
Существует множество решений для ведения журналов Java. Мне больше всего нравится SLF4J, потому что он чрезвычайно легко подключаемый и может одновременно объединять журналы из разных платформ ведения журналов. У вас есть странный проект, использующий java.util.logging, JCL и log4j? SLF4J для вас.
Двухстраничное руководство — это практически все, что вам нужно для начала работы.
Мне не нравятся тяжелые ORM-фреймворки, потому что мне нравится SQL. Итак, я написал много шаблонов JDBC, и их было сложно поддерживать. jOOQ — гораздо лучшее решение.
Он позволяет писать SQL на Java типобезопасным способом:
// Typesafely execute the SQL statement directly with jOOQ
Result < Record3 < String , String , String >> result =
create . select ( BOOK . TITLE , AUTHOR . FIRST_NAME , AUTHOR . LAST_NAME )
. from ( BOOK )
. join ( AUTHOR )
. on ( BOOK . AUTHOR_ID . equal ( AUTHOR . ID ))
. where ( BOOK . PUBLISHED_IN . equal ( 1948 ))
. fetch ();
Используя это и шаблон DAO, вы можете упростить доступ к базе данных.
Тестирование имеет решающее значение для вашего программного обеспечения. Эти пакеты помогут сделать это проще.
Хорошая альтернатива : TestNG.
jUnit не нуждается в представлении. Это стандартный инструмент для модульного тестирования в Java.
Но вы, вероятно, не используете весь потенциал jUnit. jUnit поддерживает параметризованные тесты, правила, которые не позволяют вам писать слишком много шаблонов, теории случайного тестирования определенного кода и предположения.
Если вы выполнили внедрение зависимостей, именно здесь оно и окупается: макетирование кода, имеющего побочные эффекты (например, общение с сервером REST), и при этом утверждение поведения кода, который его вызывает.
jMock — стандартный инструмент для создания макетов для Java. Это выглядит так:
public class FooWidgetTest {
private Mockery context = new Mockery ();
@ Test
public void basicTest () {
final FooWidgetDependency dep = context . mock ( FooWidgetDependency . class );
context . checking ( new Expectations () {{
oneOf ( dep ). call ( with ( any ( String . class )));
atLeast ( 0 ). of ( dep ). optionalCall ();
}});
final FooWidget foo = new FooWidget ( dep );
Assert . assertTrue ( foo . doThing ());
context . assertIsSatisfied ();
}
}
Это устанавливает FooWidgetDependency через jMock, а затем добавляет ожидания. Мы ожидаем, что метод вызова dep будет вызываться один раз с некоторой строкой, а метод optionCall dep будет вызываться ноль или более раз.
Если вам приходится настраивать одну и ту же зависимость снова и снова, вам, вероятно, следует поместить ее в тестовую фикстуру, а AssertIsSatisfied — в фикстуру @After .
Вы когда-нибудь делали это с jUnit?
final List < String > result = some . testMethod ();
assertEquals ( 4 , result . size ());
assertTrue ( result . contains ( "some result" ));
assertTrue ( result . contains ( "some other result" ));
assertFalse ( result . contains ( "shouldn't be here" ));
Это просто раздражающий шаблон. AssertJ решает эту проблему. Вы можете преобразовать тот же код в это:
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
Этот свободный интерфейс делает ваши тесты более читабельными. Чего еще можно желать?
Хорошие альтернативы : Eclipse и Netbeans.
Лучшая Java IDE — IntelliJ IDEA. Он имеет массу замечательных функций, и это действительно главное, что делает многословие Java доступным. Автозаполнение великолепно, проверки на высшем уровне, а инструменты рефакторинга действительно полезны.
Бесплатная версия сообщества меня вполне устраивает, но в версии Ultimate есть множество замечательных функций, таких как инструменты для работы с базами данных, поддержка Spring Framework и Chronon.
Одной из моих любимых особенностей GDB 7 была возможность путешествовать во времени во время отладки. Это возможно с помощью плагина Chronon IntelliJ, когда вы получаете версию Ultimate.
Вы получаете историю переменных, шаг назад, историю методов и многое другое. Немного странно использовать его в первый раз, но он может помочь в отладке некоторых действительно сложных ошибок, ошибок Heisenbugs и тому подобного.
Хорошая альтернатива : DCEVM
Непрерывная интеграция часто является целью продуктов «программное обеспечение как услуга». Что, если вам даже не нужно ждать завершения сборки, чтобы увидеть изменения кода в реальном времени?
Это то, что делает JRebel. Как только вы подключите свой сервер к клиенту JRebel, вы сразу же увидите изменения на своем сервере. Это огромная экономия времени, если вы хотите быстро поэкспериментировать.
Система типов Java довольно слаба. Он не различает строки и строки, которые на самом деле являются регулярными выражениями, а также не выполняет никаких проверок на наличие ошибок. Однако Checker Framework делает это и даже больше.
Он использует аннотации, такие как @Nullable, для проверки типов. Вы даже можете определить свои собственные аннотации, чтобы сделать статический анализ еще более эффективным.
Даже если следовать лучшим практикам, даже лучший разработчик будет совершать ошибки. Существует ряд инструментов, которые вы можете использовать для проверки вашего Java-кода и обнаружения проблем в вашем коде. Ниже представлена небольшая подборка некоторых из наиболее популярных инструментов. Многие из них интегрируются с популярными IDE, такими как Eclipse или IntelliJ, что позволяет вам быстрее обнаруживать ошибки в коде.
Помимо использования этих инструментов во время разработки, зачастую полезно запускать их на этапах сборки. Их можно привязать к инструментам сборки, таким как Maven или Gradle, а также к инструментам непрерывной интеграции.
Утечки памяти случаются даже в Java. К счастью, для этого есть инструменты. Лучший инструмент, который я использовал для решения этой проблемы, — это анализатор памяти Eclipse. Он делает дамп кучи и позволяет найти проблему.
Есть несколько способов получить дамп кучи для процесса JVM, но я использую jmap:
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created
Затем вы можете открыть файл heapdump.hprof с помощью анализатора памяти и быстро посмотреть, что происходит.
Ресурсы, которые помогут вам стать мастером Java.