1. Введение
Lombok — это простой в использовании инструмент, такой как Google Guava, который настоятельно рекомендуется здесь, каждый инженер Java должен использовать его.Lombok — это утилита Java™, которая помогает разработчикам избавиться от многословного кода Java, особенно для простых объектов Java (POJO). Это достигается с помощью аннотаций. Внедрив Lombok в среду разработки, разработчики могут сэкономить много времени на построении таких методов, как hashCode() и equals(), которые ранее использовались для классификации различных средств доступа и мутаторов.
2 IntelliJ установить Ломбок
-
Установить через Центр плагинов IntelliJ
-
Install Plugin
-
Последнее, что следует отметить, это то, что при использовании аннотаций lombok не забудьте импортировать в проект пакет lombok.jar.Если вы используете Maven Project, вам необходимо добавить зависимости в pom.xml.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.8</version>
</dependency>
3 Использование Ломбока
3.1 Описание аннотации Ломбока
-
val
: используется перед локальными переменными, что эквивалентно объявлению переменной final -
@NonNull
: добавление этой аннотации к параметру метода автоматически проверит, является ли параметр пустым в методе.Если он пуст, будет выброшено NPE (NullPointerException) -
@Cleanup
: автоматическое управление ресурсами, используемыми перед локальными переменными, будет автоматически очищать ресурсы в текущей области переменных перед выходом и автоматически генерировать код, такой как try-finally, для закрытия потока. -
@Getter/@Setter
: Используется для свойств, вам больше не нужно самостоятельно писать методы установки и получения, а также вы можете указать диапазон доступа -
@ToString
: Используемый в классах метод toString может быть автоматически переопределен, и, конечно же, могут быть добавлены другие параметры, такие как @ToString(exclude="id") для исключения атрибута id, или @ToString(callSuper=true, includeFieldNames=true ) для вызова метода toString родительского класса, включая все свойства -
@EqualsAndHashCode
: Используемые в классах методы equals и hashCode генерируются автоматически. -
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
: используется в классе, он автоматически создает конструктор без параметров и конструктор, который использует все параметры, а также конструктор, который принимает все атрибуты @NonNull в качестве параметров.Если указан параметр staticName = "of", статическая фабрика, которая возвращает также будет сгенерирован объект класса метод, что гораздо удобнее, чем использование конструктора -
@Data
: Аннотируется в классе, что эквивалентно его одновременному использованию.@ToString
,@EqualsAndHashCode
,@Getter
,@Setter
и@RequiredArgsConstrutor
Эти аннотации дляPOJO类
очень полезно -
@Value
: используется в классах, это неизменяемая форма @Data, которая эквивалентна добавлению окончательных объявлений к свойствам, предоставляя только методы получения, а не методы установки. -
@Builder
: используется в классах, конструкторах и методах, чтобы предоставить вам сложные API-интерфейсы конструктора, которые вы можете вызывать следующим образом.Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
Дополнительные инструкции для справкиBuilder -
@SneakyThrows
: автоматически генерировать проверенные исключения без явного использования оператора throws в методе. -
@Synchronized
: используется в методе, метод объявлен синхронизированным и автоматически заблокированным, а объект блокировки является частным свойством.$lock
или$LOCK
, а синхронизированный объект блокировки ключевого слова в java — это, блокировка имеет побочные эффекты для этого или его собственного объекта класса, то есть вы не можете предотвратить блокировку этого или объекта класса неконтролируемым кодом, что может вызвать условия гонки или другие ошибки потока -
@Getter(lazy=true)
: Может заменить классический шаблонный код Double Check Lock. -
@Log
: генерировать различные типы объектов журнала в соответствии с различными аннотациями, но все имена экземпляров являются журналами, и существует шесть дополнительных классов реализации.-
@CommonsLog
Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); -
@Log
Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName()); -
@Log4j
Creates log = org.apache.log4j.Logger.getLogger(LogExample.class); -
@Log4j2
Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class); -
@Slf4j
Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class); -
@XSlf4j
Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
-
3.2 Пример кода на Ломбоке
- пример val
public static void main(String[] args) {
val sets = new HashSet<String>();
val lists = new ArrayList<String>();
val maps = new HashMap<String, String>();
//=>相当于如下
final Set<String> sets2 = new HashSet<>();
final List<String> lists2 = new ArrayList<>();
final Map<String, String> maps2 = new HashMap<>();
}
- Пример @NonNull
public void notNullExample(@NonNull String string) {
string.length();
}
//=>相当于
public void notNullExample(String string) {
if (string != null) {
string.length();
} else {
throw new NullPointerException("null");
}
}
- Пример @очистки
public static void main(String[] args) {
try {
@Cleanup InputStream inputStream = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//=>相当于
InputStream inputStream = null;
try {
inputStream = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- Пример @Getter/@Setter
@Setter(AccessLevel.PUBLIC)
@Getter(AccessLevel.PROTECTED)
private int id;
private String shap;
- Пример @ToString
@ToString(exclude = "id", callSuper = true, includeFieldNames = true)
public class LombokDemo {
private int id;
private String name;
private int age;
public static void main(String[] args) {
//输出LombokDemo(super=LombokDemo@48524010, name=null, age=0)
System.out.println(new LombokDemo());
}
}
- Пример @EqualsAndHashCode
@EqualsAndHashCode(exclude = {"id", "shape"}, callSuper = false)
public class LombokDemo {
private int id;
private String shap;
}
- Примеры @NoArgsConstructor, @RequiredArgsConstructor и @AllArgsConstructor
@NoArgsConstructor
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor
public class LombokDemo {
@NonNull
private int id;
@NonNull
private String shap;
private int age;
public static void main(String[] args) {
new LombokDemo(1, "circle");
//使用静态工厂方法
LombokDemo.of(2, "circle");
//无参构造
new LombokDemo();
//包含所有参数
new LombokDemo(1, "circle", 2);
}
}
- @Пример данных
import lombok.Data;
@Data
public class Menu {
private String shopId;
private String skuMenuId;
private String skuName;
private String normalizeSkuName;
private String dishMenuId;
private String dishName;
private String dishNum;
//默认阈值
private float thresHold = 0;
//新阈值
private float newThresHold = 0;
//总得分
private float totalScore = 0;
}
- Пример @значения
@Value
public class LombokDemo {
@NonNull
private int id;
@NonNull
private String shap;
private int age;
//相当于
private final int id;
public int getId() {
return this.id;
}
...
}
- Пример @Builder
@Builder
public class BuilderExample {
private String name;
private int age;
@Singular
private Set<String> occupations;
public static void main(String[] args) {
BuilderExample test = BuilderExample.builder().age(11).name("test").build();
}
}
- Пример @SneakyThrows
import lombok.SneakyThrows;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
public class Test {
@SneakyThrows()
public void read() {
InputStream inputStream = new FileInputStream("");
}
@SneakyThrows
public void write() {
throw new UnsupportedEncodingException();
}
//相当于
public void read() throws FileNotFoundException {
InputStream inputStream = new FileInputStream("");
}
public void write() throws UnsupportedEncodingException {
throw new UnsupportedEncodingException();
}
}
- @Синхронизированный пример
public class SynchronizedDemo {
@Synchronized
public static void hello() {
System.out.println("world");
}
//相当于
private static final Object $LOCK = new Object[0];
public static void hello() {
synchronized ($LOCK) {
System.out.println("world");
}
}
}
- @Getter(lazy = true)
public class GetterLazyExample {
@Getter(lazy = true)
private final double[] cached = expensive();
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
// 相当于如下所示:
import java.util.concurrent.atomic.AtomicReference;
public class GetterLazyExample {
private final AtomicReference<java.lang.Object> cached = new AtomicReference<>();
public double[] getCached() {
java.lang.Object value = this.cached.get();
if (value == null) {
synchronized (this.cached) {
value = this.cached.get();
if (value == null) {
final double[] actualValue = expensive();
value = actualValue == null ? this.cached : actualValue;
this.cached.set(value);
}
}
}
return (double[]) (value == this.cached ? null : value);
}
private double[] expensive() {
double[] result = new double[1000000];
for (int i = 0; i < result.length; i++) {
result[i] = Math.asin(i);
}
return result;
}
}
4 Принцип аннотации Ломбока
Говоря о Lombok, мы должны упомянуть JSR 269: Pluggable Annotation Processing API (Ууууу.Basics.org/En/Hiashi Joo/He…). До JSR 269 у нас также был такой артефакт, как аннотация, но, например, мы должны использовать отражение для того, что хотим сделать, а метод отражения более ограничен.Прежде всего, он должен определить @Retention как RetentionPolicy.RUNTIME, который может получать значения аннотации только через отражение во время выполнения, что снижает эффективность кода времени выполнения.. Во-вторых, если вы хотите использовать аннотации для выполнения каких-то проверок на этапе компиляции и выдачи отчетов об ошибках на какие-то неразумные коды пользователя, использование рефлексии бессильно.После JSR 269 мы можем использовать аннотации для выполнения этих задач во время компиляции Javac.. Итак, мы нашлиРазличие между ядром находится во время выполнения или во время компиляции..
Как видно из рисунка выше, обработка аннотаций — это шаг между синтаксическим анализом и генерацией. Подробные шаги следующие:
На приведенном выше рисунке показан процесс обработки Lombok.После анализа Javac в абстрактное синтаксическое дерево (AST) Lombok динамически модифицирует AST в соответствии со своим собственным процессором аннотаций, добавляет новые узлы (так называемый код) и, наконец, анализирует и генерирует байт-коды..
Начиная с Java 6, javac поддерживает спецификацию «JSR 269 Pluggable Annotation Processing API». Пока программа реализует этот API, его можно вызывать во время работы javac..
- Инструмент компиляции Java, используемый Maven, широко используемый инструмент управления проектами, исходит из настроенного стороннего инструмента.Если мы настроим этот сторонний инструмент как Oracle javac, то Maven будет напрямую поддерживать lombok;
- Если инструментом компиляции, настроенным Intellij Idea, является Oracle javac, он будет напрямую поддерживать lombok;
Решение проблем с инструментом IDE:
Теперь есть класс A, в котором есть некоторые поля, нет методов установки и получения для их создания с использованием аннотации @Data ломбока, и еще один класс B, который вызывает методы установки и получения соответствующих полей экземпляра класса A.
Скомпилируйте проект, в котором расположены класс A и класс B, и об ошибке не будет сообщено, потому что в окончательном сгенерированном файле байт-кода класса A есть методы установки и получения для соответствующих полей.
Однако среда IDE обнаруживает, что методы установки и получения экземпляра класса A, используемые в исходном коде класса B, не могут быть определены в исходном коде класса A, и среда IDE сочтет это ошибкой.
Чтобы исправить указанную выше ошибку, которая не является реальной ошибкой, вы можете загрузить и установить «плагин Lombok» в Intellij Idea.
5 пользовательских аннотаций, поддерживающих JSR269
В общем процессе компиляции javac файл java сначала создает AST путем анализа, затем выполняет обработку аннотаций и, наконец, генерирует двоичный файл .class посредством анализа и оптимизации.Что мы можем сделать, так это выполнить соответствующую обработку на этапе обработки аннотаций.. Сначала мы создаем следующие файлы в META-INF.services:
В файле указан наш процессор аннотаций:com.alipay.kris.other.lombok.MyAnnotaionProcessor
, а затем мы можем написать собственный обработчик аннотаций, простой пример кода выглядит следующим образом:
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("com.alipay.kris.other.lombok.*")
public class MyAnnotaionProcessor extends AbstractProcessor {
public MyAnnotaionProcessor() {
super();
}
@Override
public boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv) {
for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
MyAnnotation annotation = elem.getAnnotation(MyAnnotation.class);
String message = "annotation found in " + elem.getSimpleName()
+ " with " + annotation.value();
addToString(elem);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
}
return true; // no further processing of this annotation type
}
}