Цикл статей «Project Lombok».
Следующая статья — «Lombok @Builder».
Предыдущая статья — «Lombok @Data».
Аннотация @Value впервые появилась в качестве экспериментальной возможности в Lombok v0.11.4.
@Value больше не предполагает @Wither с lombok v0.11.8.
@Value продвинулась в основной пакет Lombok с Lombok v0.12.0.
@Value — это неизменяемый вариант @Data. Все поля делаются приватными и final по умолчанию, методы установки значений не генерируются. Класс тоже делается final, потому что неизменяемость — это не то, что распространяется на подклассы. Так же как и в @Data, методы toString(), equals() и hashCode() methods генерируются, каждое поле получает метод получения значения, генерируется конструктор, покрывающий все аргументы (кроме полей final, инициализированных при объявлении).
Практически @Value является сокращением для final @ToString @EqualsAndHashCode @AllArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @Getter, кроме того, что при явном включении реализации любого из методов эта часть не будет генерироваться, и никаких ошибок и предупреждений возникать не будет. Например, если вы напишете свой метод toString, то никаких ошибок возникать не будет, и Lombok не будет генерировать toString. Также любой явный конструктор, независимо от списка аргументов, подразумевает, что Lombok не будет генерировать конструктор. Если вы хотите, чтобы Lombok генерировал конструктор со всеми полями, то добавьте @AllArgsConstructor к классу. Вы можете пометить любой конструктор или метод аннотацией @lombok.experimental.Tolerate, чтобы скрыть их от Lombok.
Можно переопределить final-по-умолчанию и private-по-умолчанию с помощью явного указания уровня доступа для поля или с помощью аннотаций @NonFinal или @PackagePrivate.
Можно переопределить любое поведение любой «части» @Value с помощью явного указания соответствующих аннотаций.
С помощью Lombok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import lombok.AccessLevel; import lombok.experimental.NonFinal; import lombok.experimental.Value; import lombok.experimental.Wither; import lombok.ToString; @Value public class ValueExample { String name; @Wither(AccessLevel.PACKAGE) @NonFinal int age; double score; protected String[] tags; @ToString(includeFieldNames = true) @Value(staticConstructor = "of") public static class Exercise<T> { String name; T value; } } |
Чистая Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import java.util.Arrays; public final class ValueExample { private final String name; private int age; private final double score; protected final String[] tags; @java.beans.ConstructorProperties({ "name", "age", "score", "tags" }) public ValueExample(String name, int age, double score, String[] tags) { this.name = name; this.age = age; this.score = score; this.tags = tags; } public String getName() { return this.name; } public int getAge() { return this.age; } public double getScore() { return this.score; } public String[] getTags() { return this.tags; } @java.lang.Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof ValueExample)) return false; final ValueExample other = (ValueExample) o; final Object this$name = this.getName(); final Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name .equals(other$name)) return false; if (this.getAge() != other.getAge()) return false; if (Double.compare(this.getScore(), other.getScore()) != 0) return false; if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false; return true; } @java.lang.Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $name = this.getName(); result = result * PRIME + ($name == null ? 43 : $name.hashCode()); result = result * PRIME + this.getAge(); final long $score = Double.doubleToLongBits(this.getScore()); result = result * PRIME + (int) ($score >>> 32 ^ $score); result = result * PRIME + Arrays.deepHashCode(this.getTags()); return result; } @java.lang.Override public String toString() { return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")"; } ValueExample withAge(int age) { return this.age == age ? this : new ValueExample(name, age, score, tags); } public static final class Exercise<T> { private final String name; private final T value; private Exercise(String name, T value) { this.name = name; this.value = value; } public static <T> Exercise<T> of(String name, T value) { return new Exercise<T>(name, value); } public String getName() { return this.name; } public T getValue() { return this.value; } @java.lang.Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof ValueExample.Exercise)) return false; final Exercise<?> other = (Exercise<?>) o; final Object this$name = this.getName(); final Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name .equals(other$name)) return false; final Object this$value = this.getValue(); final Object other$value = other.getValue(); if (this$value == null ? other$value != null : !this$value .equals(other$value)) return false; return true; } @java.lang.Override public int hashCode() { final int PRIME = 59; int result = 1; final Object $name = this.getName(); result = result * PRIME + ($name == null ? 43 : $name.hashCode()); final Object $value = this.getValue(); result = result * PRIME + ($value == null ? 43 : $value.hashCode()); return result; } @java.lang.Override public String toString() { return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")"; } } } |
Поддерживаемые ключи конфигурации
1 |
lombok.value.flagUsage = [warning | error] (default: not set) |
Lombok будет помечать любое использование @Value предупреждением или ошибкой, если настроено.
Примечание
Смотрите статьи про «части» @Value: @ToString, @EqualsAndHashCode, @AllArgsConstructor, @FieldDefaults, and @Getter.
Для классов с шаблонами полезно иметь статический метод, который действует как конструктор, потому что вывод параметров шаблона для статических методов работает в Java6 и исключает необходимость использования оператора <>. Вы можете сделать это с помощью явного указания @AllArgsConstructor(staticConstructor="of"), и также есть @Value(staticConstructor="of"), которые делает конструктор со всеми аргументами приватным и генерирует публичный статический метод с именем of, который оборачивается вокруг приватного конструктора.
Аннотация @Value была экспериментальной возможностью с v0.11.4 по v0.11.9 (как @lombok.experimental.Value). С тех пор она переместилась в основной пакет. Старая аннотация всё ещё есть, но со временем она будет удалена.
Можно использовать @FieldDefaults, чтобы отменить private-по-умолчанию и final-по-умолчанию для полей класса. Используйте @NonFinal и @PackagePrivate для полей класса, чтобы переопределить это поведение.
Цикл статей «Project Lombok».
Следующая статья — «Lombok @Builder».
Предыдущая статья — «Lombok @Data».
Ошибка в: «Например, если вы напишете свой метод toString, то никаких ошибок возникать не будет, и Lombok будет генерировать toString.»
Должно быть: «Например, если вы напишете свой метод toString, то никаких ошибок возникать не будет, и Lombok НЕ будет генерировать toString.»
Оригинал: «For example, if you write your own toString, no error occurs, and lombok will not generate a toString.»
Исправил, спасибо.