Недавно открыл для себя хорошую вещь.На первый взгляд она потрясающая.Всякие черные технологии.При ближайшем рассмотрении действительно очень удобный и практичный инструмент.GithubНа нем 5000+ звезд, отличный проект.
Lombok предоставляет много сладкого синтаксического сахара для Java, а дизайн также очень разумен, многие из которых соответствуют лучшим практикам, описанным в «Эффективной Java». Так что комбинируйтеофициальная документацияИ некоторые из их собственной практики, чтобы дать вам подробное введение.
инструкции
В настройках-> плагины и включить плагин ломбок
Затем pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>
После завершения вы можете начать использовать его, большинство из которых представлены в виде аннотаций для выполнения некоторых определений или функциональных улучшений.
val
может представлять любой тип
локальные переменные, недоступные для переменных экземпляра
Этот тип будет выводиться из инициализированного выражения, и он похож на динамический язык, но не
Это значение является окончательным, должно быть начальное выражение присваивания, и его нельзя переназначить.
Пример:
val i="string";
val list=new ArrayList<String>();
s.ensureCapacity(23);
System.out.println(i);
Эквивалентно:
final String i="asd";
final ArrayList<String> s=new ArrayList<>();
s.ensureCapacity(23);
System.out.println(i);
@NonNull
Не может быть пустым, если пусто, NullPointerException будет выброшено напрямую
В исходном коде объявлено, что его можно использовать в переменных-членах, методах, параметрах и локальных переменных, но реальный тест может работать правильно только в параметрах и переменных-членах.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface NonNull {
}
Пример:
public class User {
@NonNull
private String name;
public void setName(String name) {
this.name = name;
}
}
@Test
public void main() throws Exception{
User user=new User();
user.setName(null);
}
@Test
public void main() throws Exception{
display(null);
}
private void display(@NonNull String source){
System.out.println(source);
}
Эквивалентно:
private void display(String source){
if(source == null) {
throw new NullPointerException("source");
}
System.out.println(source);
}
Следующее не даст ошибки
@Test
public void main() throws Exception{
@NonNull Integer i=null;
i=null;
System.out.println("success");
}
@NonNull
private void display(String source){
System.out.println(source);
}
@Cleanup
Доступно только для локальных переменных
Доступны только ресурсы для выпуска, именно для достижения класса Closeable, иначе при компиляции произойдет ошибка, но IDEA не жалуется
Объявите, что эта переменная аннотации автоматически освобождает ресурсы в конце
Принцип состоит в том, чтобы добавить try{}finally(x.close);
Пример:
@Test
public void main() throws Exception{
@Cleanup InputStream is=new FileInputStream(new File("D: estaa.txt"));
System.out.println();
}
Декомпилировать класс, созданный приведенным выше кодом
@Test
public void main() throws Exception {
FileInputStream is = new FileInputStream(new File("D: estaa.txt"));
try {
System.out.println();
} finally {
if(Collections.singletonList(is).get(0) != null) {
is.close();
}
}
}
Этот способ записи также эквивалентен тому, что используется в JDK1.7.
@Test
public void main() throws Exception{
try(InputStream is=new FileInputStream(new File("D: estaa.txt"))){
System.out.println();
}
}
Но удобнее использовать такие аннотации.
@Getter and @Setter
для переменных-членов и классов
Установить и получить методы, которые могут напрямую создавать переменные-члены
как:
public class User {
@Getter
@Setter
private Integer id;
@Setter
@Getter
private String name;
}
Готов к использованию сейчас
@Test
public void main() throws Exception{
User user=new User();
user.setId(1);
System.out.println(user.getId());
}
Вы также можете объявить его непосредственно в классе, тогда все переменные класса будут генерировать методы get и set.
@Getter
@Setter
public class User {
private Integer id;
private String name;
}
Вы можете указать уровни доступа PUBLIC, PROTECTED, PACKAGE и PRIVATE, по умолчанию — PUBLIC.
@Setter(AccessLevel.PROTECTED)
@ToString
можно использовать для занятий
Переопределить метод toString() по умолчанию, который будет отображать основную информацию о классе.
@Test
public void main() throws Exception{
User user=new User();
user.setId(1);
user.setName("bb");
System.out.println(user.toString());
}
//输出:User(id=1, name=Asens)
Опции:
includeFieldNames: если false, не отображать имена переменных
@ToString(includeFieldNames=false)
//输出:User(1, Asens)
исключить: какие поля не отображаются
@ToString(exclude={"id"})
//输出:User(name=Asens)
of: только какие поля отображать
@ToString(of={"id"})
//输出:User(id=1)
@EqualsAndHashCode
только для занятий
Переопределить значения по умолчанию и hashCode
Методы и параметры похожи на @tostring
В дополнение к общим реализациям equals и hashCode можно использовать или exclude, и hashCode будет рассчитываться только для тех или иных полей, сравниваемых или нет.
@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor
применимы только к классу
@NoArgsConstructor
Будет создан конструктор без параметров. Класс имеет конструктор без параметров по умолчанию, но если конструктор без параметров создан, функция без параметров исчезнет. Эта аннотация эквивалентна добавлению конструктора без параметров. Конструктор и добавляет некоторые новые функции.
Если есть конечное поле, произойдет ошибка компиляции, если не используется @NoArgsConstructor(force = true), тогда все конечные поля будут определены как 0, false, null и т. д.
@RequiredArgsConstructor
Используйте эту аннотацию для создания конструкторов с соответствующими параметрами для полей final и @NonNull.
Если я установлю, имя не может быть нулевым
@Getter
@Setter
@RequiredArgsConstructor
public class User {
private Integer id;
@NonNull
private String name;
}
Поэтому, когда вы звоните, только конструктор имени
Если я также установлю идентификатор @NonNull
затем при появлении запроса становится
@AllArgsConstructor
Как следует из названия, генерируется конструктор с полными параметрами, который будет работать с @NonNull.
@Getter
@Setter
@ToString
@AllArgsConstructor
public class User {
private Integer id;
@NonNull
private String name;
}
Декомпилировать сгенерированный код
@ConstructorProperties({"id", "name"})
public User(Integer id, @NonNull String name) {
if(name == null) {
throw new NullPointerException("name");
} else {
this.id = id;
this.name = name;
}
}
Все три имеют параметр staticName, который можно использовать для превращения конструктора в статический фабричный метод.
В настоящее время Пользователь больше не может быть новым, и можно использовать только метод статической фабрики.
Вы также можете использовать доступ для управления областью доступа класса
@AllArgsConstructor(staticName = "of")
User user=User.of(1,"Asens");
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Data
@ToString
@EqualsAndHashCode
@Getter
@Setter
@RequiredArgsConstructor
коллекция
Вы можете использовать staticConstructor для достижения функции вышеуказанного staticName
@Data(staticConstructor="of")
@Value
только для занятий
@Value используется для создания неизменяемых классов. Как и @Data, @Value также представляет собой набор аннотаций.
соответственно включают
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@Getter
Разница в том, что @Setter больше не предоставляется, каждая переменная-член является окончательной и закрытой, а создание экземпляра должно предоставлять все параметры для инициализации.
@Builder
Если вы знакомы с шаблоном построителя, то вы должны знать, сколько проблем с шаблоном построителя
Если вы не знаете, вы можете обратиться к моей предыдущей статье:https://zhuanlan.zhihu.com/p/27850975
Режим построителя обычно такой (уменьшенные переменные-члены, только одна переменная-член обычно не использует этот режим)
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(Builder builder) {
this.name= builder.name;
}
public static Builder builder(){
return new Builder();
}
public static class Builder{
private String name;
public Builder name(String name) {
this.name= name;
return this;
}
public User build(){
return new User(this);
}
}
}
После использования @Builder просто нужно это
@Builder
@Getter
@Setter
public class User {
private String name;
}
Оба звонят одинаково
@Test
public void main() throws Exception{
User user=User.builder().name("Asens").build();
System.out.println(user.getName());
}
@SneakyThrows
Если в методе есть проверенное исключение, эту аннотацию можно использовать без объявления исключения, соответствующего броскам в методе.
Например, при чтении файла FileNotFoundException — это проверенное исключение, которое нужно генерировать с помощью try, catch или throws.
private void read() throws FileNotFoundException {
File file=new File("D: estaa.txt");
InputStream is = new FileInputStream(file);
//ignore
}
Затем используйте @SneakyThrows, чтобы напрямую игнорировать проверенные исключения.
Но нет никакой разницы в реальном процессе эксплуатации и брошенном.
@SneakyThrows
private void read() {
File file=new File("D: estaa.txt");
InputStream is = new FileInputStream(file);
}
Это декомпилированный код
private void read() {
try {
File $ex = new File("D: estaa.txt");
new FileInputStream($ex);
} catch (Throwable var3) {
throw var3;
}
}
Этот декомпилированный код не может быть скомпилирован [мозг наполняется улыбкой и плачем]
Причина в том, что исключение будет вызвано во время выполнения независимо от того, объявляет ли метод броски или нет.
Но во время компиляции, пока выдается проверенное исключение, оно должно быть объявлено
Так что это может быть достигнуто
Но используйте его с осторожностью.Как правильно использовать исключения - это знание.Рекомендуется прочитать соответствующие главы "Effective Java"
@Synchronized
Как следует из названия, блокировки доступны только на уровне метода.
Пример:
@Test
public void mm() throws FileNotFoundException {
aa();
}
@Synchronized
private void aa(){
System.out.println();
}
после декомпиляции
private final Object $lock = new Object[0];
public TestS() {
}
@Test
public void mm() throws FileNotFoundException {
this.aa();
}
private void aa() {
Object var1 = this.$lock;
synchronized(this.$lock) {
System.out.println();
}
}
Эта блокировка не используется в методе, но блокирует всю внутреннюю часть метода, по ощущениям не сильно отличается от добавления synchronized непосредственно в метод, а эффективность немного выше.
@Getter(lazy=true)
ленивая загрузка
Доступно для переменных класса и члена
Для некоторых операций не требуется загрузка в момент инициализации, а нужно дождаться, пока она будет загружена, в это время требуется отложенная загрузка.
Для поля вам нужен финал
Мы определяем пользователя, мы хотим присвоить значение имени, когда getName
@Setter
@Getter
public class User {
private Integer id;
@Getter(lazy=true)
private final String name=makeName();
private String makeName() {
System.out.println("make name");
return "aa";
}
}
перечислить
@Test
public void mm() throws FileNotFoundException {
User user=new User();
System.out.println("before user get name");
user.getName();
System.out.println("after user get name");
}
输出:
before user get name
make name
after user get name
MakeName выполняется, когда пользователь находится в getName
Для сравнения убери ленивый
@Setter
@Getter
public class User {
private Integer id;
private final String name=makeName();
private String makeName() {
System.out.println("make name");
return "aa";
}
}
позвоните еще раз, очевидно
@Test
public void mm() throws FileNotFoundException {
User user=new User();
System.out.println("before user get name");
user.getName();
System.out.println("after user get name");
}
输出:
make name
before user get name
after user get name
Принцип реализации, наверное, такой, что-то вроде
public class User {
private Integer id;
private String name=null;
private String makeName() {
System.out.println("make name");
return "aa";
}
public String getName() {
if(name!=null) return name;
return name=makeName();
}
}
Но это немного грубо, мы не можем ни добиться имени окончательного, ни сохранить поток безопасности, два потока одновременно обращаются, вызываются дважды правильно правильно makeName
Чтобы решить вышеуказанные проблемы, ломбок решил это так
после декомпиляции
public class User {
//省略其他代码
private final AtomicReference<Object> name = new AtomicReference();
public String getName() {
Object value = this.name.get();
if (value == null) {
AtomicReference var2 = this.name;
synchronized(this.name) {
value = this.name.get();
if (value == null) {
String actualValue = this.makeName();
value = actualValue == null ? this.name : actualValue;
this.name.set(value);
}
}
}
return (String)((String)(value == this.name ? null : value));
}
}
В первую очередь переменная становится контейнером, сам контейнер не меняется, но может быть прочитан и записан, а чтение и запись самого AtomicReference атомарны, а использование synchronized при вызове makeName и присвоении значений обеспечивает поток безопасность.
@Log
Как вы написали этот журнал?
Для того, чтобы показать отличие наших собственных продуктов, способы написания различных журналов также имеют свои особенности.Каждый раз, когда вы создаете новый класс, вам приходится копировать журнал в другом классе, а затем менять имя класса.То же самое. одноклассники, поднимите руки...
lombok резюмирует написание различных журналов
В реальном использовании он полностью бесшовный и полностью эквивалентен функции, переданной аннотацией, которая является лаконичной и элегантной.
@Controller
@Slf4j
public class SampleController {
//private static Logger log= LogManager.getLogger(SampleController.class);
@RequestMapping("/")
public String home(ModelMap model) {
log.info("aa");
return "main";
}
}
Ломбок также имеет серию функций реализации природы, эти функции могут не быть такими элегантными, нет полного теста, и функции могут быть удалены или значительно изменены в будущем
Если интересно, можете посмотреть
https://projectlombok.org/features/experimental/all
Вы можете следить за моей колонкой, чтобы увидеть больше технических статей по Java.