Lombok — проект по добавлению дополнительной функциональности в Java c помощью изменения исходного кода перед Java компиляцией.
По сути, проект Lombok позволяет избавиться от многословности Java в большинстве случаев и перестать писать огромные простыни кода из гетеров, сеттеров, equals, hashcode и toString (да их обычно генерит IDE, но читать и менять все равно приходится программисту), в результате Java становиться почти такой же краткой как Kotlin, Scala или C#.
Что особенно радует, Lombok очень прост и легок в добавлении к вашему проекту. Если вам, как и мне, нравится принцип KISS, то советую посмотреть на Lombok.
и т.п. Если вы собираете Gradle или Maven, то собираться будет и без этих плагинов, но будут Idea/Eclipse возможно будут показывать ошибки при анализе кода.
Название |
Описание |
Пример Lombok
|
Пример обычной Java
|
---|
@NonNull |
обработка переменных,
которые не должны получать null |
public Example(@NonNull P p) {
super("Hello");
this.name = p.getName();
}
|
public Example(@NonNull P p) {
super("Hello");
if (p == null) {
throw new NullPointerException("p");
}
this.name = p.getName();
}
|
@Getter /
@Setter |
легкое создание getter’ов и
setter’ов |
@Getter
@Setter
private int age = 10;
|
private int age = 10;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
|
@ToString |
определение аннотации перед классом,
для реализации стандартного toString метода |
@ToString(exclude="f")
public class Example
|
public class Example {
@Override
public String toString() {
return ...;
}
|
@EqualsAndHashCode |
легкое создание методов Equals и HashCode |
@EqualsAndHashCode(
exclude={"id1", "id2"})
public class Example {
|
public class Example {
...
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
|
@NoArgsConstructor,
@RequiredArgsConstructor,
@AllArgsConstructor |
создания пустого конструктора,
конструктора включающего все final поля,
либо конструктора включающего все возможные поля |
@RequiredArgsConstructor(
staticName = "of"
)
@AllArgsConstructor(
access = AccessLevel.PROTECTED
)
public class E<T> {
|
public class E<T> {
private E(T description) {
...
}
public static <T>E<T> of(
T description
) {
return new E<T>(description);
}
|
@Data |
генерация всех служебных методов,
заменяет сразу команды @ToString, @EqualsAndHashCode,
Getter, Setter, @RequiredArgsConstructor |
@Data
public class Example {
private final String name;
private int age;
}
|
[spoiler=Много кода]public class Example {
private final String name;
private int age;
public Example(
String name
) {
this.name = name;
}
public String getName() {
return this.name;
}
void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
@Override
public String toString() {
return ...;
}
@Override
public boolean equals(
Object o
) {
....
}
@Override
public int hashCode() {
...
}
[/spoiler]
|
@Value |
создание неизменяемых классов,
аналог Data, но для неизменяемых классов |
@Value
public class Example {
private final String name;
private int age;
}
|
[spoiler=Много кода]public class Example {
private final String name;
private final int age;
public Example(
String name, int age
) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
@Override
public String toString() {
return ...;
}
@Override
public boolean equals(
Object o
) {
....
}
@Override
public int hashCode() {
...
}
[/spoiler]
|
@Builder |
реализация паттерна bulder,
Singular – используется для объектов в
единственном экземпляре (добавления элемента
в коллекции и т.п.) |
@Builder
public class Example {
private String name;
private int age;
@Singular
private Set<String> occupations;
}
|
[spoiler=много кода]public class Example {
private String name;
private int age;
private Set<String> occupations;
Example(
String name,
int age,
Set<String> occupations
) {
this.name = name;
this.age = age;
this.occupations = occupations;
}
public static ExampleBuilder builder() {
return new ExampleBuilder();
}
public static class ExampleBuilder {
private String name;
private int age;
private ArrayList<> occupations;
ExampleBuilder() {
}
public ExampleBuilder name(
String name
) {
this.name = name;
return this;
}
public ExampleBuilder age(
int age
) {
this.age = age;
return this;
}
public ExampleBuilder occupation(
String occupation
) {
if (this.occupations == null) {
this.occupations =
new ArrayList<String>();
}
this.occupations.add(occupation);
return this;
}
...
public Example build() {
Set<String> occupations = ...;
return new Example(name, age, occupations);
}
@java.lang.Override
public String toString() {
...
}
}
}
[/spoiler]
|
@SneakyThrows |
обертка проверяемых исключений |
@SneakyThrows(
UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, «UTF-8»);
}
|
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw Lombok.sneakyThrow(e);
}
}
|
@Synchronized |
простое создание synchronized блоков |
private final Object readLock = new Object();
@Synchronized
public static void hello() {
...;
}
@Synchronized
public int answerToLife() {
...
}
@Synchronized("readLock")
public void foo() {
...
}
|
[spoiler=Много кода]private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
public static void hello() {
synchronized($LOCK) {
...
}
}
public int answerToLife() {
synchronized($lock) {
...
}
}
public void foo() {
synchronized(readLock) {
...
}
}
[/spoiler]
|
@Log |
добавление инницилизации логирования,
так же позволяет выбрать вид логгера: @CommonsLog,
@JBossLog, Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j |
@Slf4j
public class Example {
public static void main(String... args) {
log.error("error");
}
|
public class Example {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
public static void main(String... args) {
log.error("error");
}
|
Val |
простое создание финальной
переменной с выводом типа,
то есть то самый val о котором
спорили |
val map = new HashMap<Integer, String>();
for (val entry : map.entrySet()) {
...
}
|
final HashMap<Integer, String> map = new HashMap<Integer, String>();
...
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
...
}
|
@Cleanup |
простое определение ресурсов,
так чтобы они автоматически закрывались
после окончания работы кода.
(не так актуально при использовании
try with resources ) |
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
...
|
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
...
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
|
Примеры кода частично взял с сайта проекта Lombok (cократив), если интересно больше подробностей см. официальный сайт
.