User Victor Sergeev
Victor Sergeev
Level 40
St. Petersburg

Annotations. Part 2. Lombok

Published in the Java Developer group
Annotations. Part 1 — a little boring In this part, I decided to touch on the Lombok library, as it is a well-known representative of source code annotations. I'll address runtime annotations in the next article. Annotations. Part 2. Lombok - 1Once upon a time, there was a Java programmer. Every day she wrote ordinary code, for example, like this:

package lombok;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
This class is ordinary — only 2 fields (after all, there are sometimes more than 10-15 fields). Of course, all this can be generated in the IDE. But damn it, that takes its place. If there are 15-20 fields, each of them needs getters, setters, constructors... Among all these, a couple of other methods, invisible to the eye, could easily be lost. How do we help this programmer write faster and less? Lombok. Out of the frying pan and into the fire with you. Here's the same class, but now we use Lombok:

package lombok;

@Data
public class Person {
    private String name;
    private int age;
}

That's all. Cool, huh? What does the @Data annotation do? During compilation, this annotation generates getters/setters for all fields, and overrides toString(), equals(), and hashCode() according to standard rules. You can install the plugin in the IDE. It will see any methods that have not yet been created. Annotations. Part 2. Lombok - 2At this point, I hope you, my reader, have become interested, because what follows will be a brief introduction with links to details. Lombok also lets you customize code generation, e.g. all getters and setters are not always needed, or you may need a different algorithm to generate a hash code. To accomplish this, there are separate annotations (I think many of them won't need a description): @Getter/@Setter, @ToString, @EqualsAndHashCode, @NoArgsConstructor, @RequiredArgsConstructor, and @AllArgsConstructor, @Log These are the most common. The whole set can be seen here. Pay special attention to var and val. This means you can write code like this:

package lombok;

import lombok.experimental.var;

@Data
public class Person {
    private String name;
    private int age;

    public static void main(String[] args) {
        var person = new Person();
        person.setAge(22);
        System.out.println(person);
    }
}

Why is this necessary? For example, we have a RandomAccessFileChannel class. Why would we want to write code like this?

RandomAccessFileChannel channel = new RandomAccessFileChannel();
If we can do this?

var channel2 = new RandomAccessFileChannel();
In my opinion, this is not always acceptable. For example, we have an evil method that returns an evil map:

public static Map<List<Set<Integer>>, Set<List<String>>> evilMap() {
    return new HashMap<>();
}

If you call it like this:

Map<List<Set<Integer>>, Set<List<String>>> listSetMap = evilMap();
Then it is more or less clear what we are working with. If the call is like this:

var listSetMap = evilMap();
then only the devil knows what evilMap() will return there, and until you look at the method itself, you don't know. Why go running around the source files? In general, you need to be careful with this. Annotations. Part 2. Lombok - 3Experimental branch: Here I want to mention the @UtilityClass annotation. It creates a private constructor that throws an exception (so grubby little hands don't use reflection to meddle there). And it is very beautiful at the beginning of a class — it tells us that there are utility methods. The @Delegate annotation implements the delegation pattern. Suppose you have a class that delegates something to another class, and you makes changes to only some of the methods — this annotation will save you from duplicating methods and it will keep track of them. If you remove or add a method, this annotation will notice. Experimental annotations branch GitHub Official website In order for the IDE to work properly with lombok and not highlight methods as non-existent, you must install the plugin. The official website has a setup section where you can see how to connect the plugin for each IDE. As you can see, lombok is popular: >5,000 stars and >1,000 forks. Spring uses lombok in its classes. If you have Spring in your project, take a look — it may have pulled lombok in without your knowledge.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION