searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

"Java Bug之路"-你踩过@Builder的坑吗?

2024-04-07 03:35:20
41
0

这篇文章深入探讨了Java编程中使用@Builder注解时可能遇到的问题。通过三个主要内容:@Builder是个啥、@Builder被编译成了啥、@Builder容易踩坑的地方,作者详细讨论了@Builder注解的定义、编译结果以及常见的陷阱。读者将通过本文全面了解@Builder注解的使用方法和潜在问题,为避免类似困扰提供了宝贵的指导。

一、@Builder是个啥

`@Builder`是Lombok项目中提供的一个注解,用于自动生成构造器方法。在Java中,通常我们需要为类编写多个构造器方法,包括无参构造器、有参构造器等,而使用`@Builder`注解可以简化这个过程。

当我们在类上使用`@Builder`注解时,Lombok会自动生成一个名为`builder()`的静态方法,通过该方法可以创建该类的实例,并且可以链式调用设置属性的方法。这样可以避免编写繁琐的构造器方法。

以下是一个简单的示例,演示如何在Java类中使用`@Builder`注解:

```java
import lombok.Builder;
import lombok.Getter;

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

// 在其他地方使用
Person person = Person.builder()
                .name("Alice")
                .age(30)
                .build();
```

在这个示例中,我们使用`@Builder`注解为`Person`类生成了一个静态的`builder()`方法,可以通过该方法创建`Person`对象,并使用链式调用设置属性的值。这样可以简化对象的创建过程。

 

二、@Builder被编译成了啥

当一个类使用了 @Builder 注解后,在编译过程中会生成一个包含构建者模式代码的静态内部类 Builder。以下是一个简单的示例,演示了一个使用 @Builder 注解的类在编译后生成的构建者模式代码:

原始类:

```java
import lombok.Builder;
import lombok.Data;

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

编译后的代码大致如下:

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

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

    public static PersonBuilder builder() {
        return new PersonBuilder();
    }

    public static class PersonBuilder {
        private String name;
        private int age;

        PersonBuilder() {
        }

        public PersonBuilder name(String name) {
            this.name = name;
            return this;
        }

        public PersonBuilder age(int age) {
            this.age = age;
            return this;
        }

        public Person build() {
            return new Person(name, age);
        }
    }
}
```

在编译后的代码中,可以看到生成了一个名为 PersonBuilder 的静态内部类,该类包含了与原始类 Person 中字段对应的 setter 方法,以及一个 build 方法用于构建 Person 对象。通过调用静态方法 builder() 可以获取到 PersonBuilder 对象,然后可以使用链式调用的方式设置字段的值,最后调用 build() 方法构建出 Person 对象。

 

三、@Builder 容易踩坑的地方

1. 循环引用:假设有两个类 A 和 B,彼此引用对方作为字段,使用 @Builder 可能会导致循环引用。例如:

```java
@Data
@Builder
public class A {
    private B b;
}

@Data
@Builder
public class B {
    private A a;
}

A a = A.builder().b(B.builder().a(a).build()).build();
```

在这种情况下,会导致循环引用,可能会出现栈溢出或无限递归。

2. 默认值设置:在 @Builder 中设置字段的默认值时,要确保正确设置。例如:

```java
@Data
@Builder
public class Person {
    @Builder.Default
    private String name = "Unknown";
}

Person person = Person.builder().build();
System.out.println(person.getName()); // 输出:Unknown
```

3. 继承:默认情况下,@Builder 不会继承父类的字段。如果需要继承父类的字段,可以使用 @SuperBuilder 注解,且父子类都需要加上这个注解。例如:

```java
@Data
@SuperBuilder
public class Parent {
    private String parentField;
}

@Data
@SuperBuilder
public class Child extends Parent {
    private String childField;
}

Child child = Child.builder().parentField("Parent").childField("Child").build();
System.out.println(child.getParentField()); // 输出:Parent
System.out.println(child.getChildField()); // 输出:Child
```

4. 构造函数:@Builder 生成的对象没有公共构造函数。如果需要手动添加构造函数,要注意与 @Builder 的兼容性。例如:

```java
@Data
@Builder
public class ConstructorExample {
    private String field1;
    private String field2;
    
    public ConstructorExample(String field1, String field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

ConstructorExample example = ConstructorExample.builder().field1("Value1").field2("Value2").build();
System.out.println(example.getField1()); // 输出:Value1
System.out.println(example.getField2()); // 输出:Value2
```

 

0条评论
作者已关闭评论
l****n
4文章数
0粉丝数
l****n
4 文章 | 0 粉丝
原创

"Java Bug之路"-你踩过@Builder的坑吗?

2024-04-07 03:35:20
41
0

这篇文章深入探讨了Java编程中使用@Builder注解时可能遇到的问题。通过三个主要内容:@Builder是个啥、@Builder被编译成了啥、@Builder容易踩坑的地方,作者详细讨论了@Builder注解的定义、编译结果以及常见的陷阱。读者将通过本文全面了解@Builder注解的使用方法和潜在问题,为避免类似困扰提供了宝贵的指导。

一、@Builder是个啥

`@Builder`是Lombok项目中提供的一个注解,用于自动生成构造器方法。在Java中,通常我们需要为类编写多个构造器方法,包括无参构造器、有参构造器等,而使用`@Builder`注解可以简化这个过程。

当我们在类上使用`@Builder`注解时,Lombok会自动生成一个名为`builder()`的静态方法,通过该方法可以创建该类的实例,并且可以链式调用设置属性的方法。这样可以避免编写繁琐的构造器方法。

以下是一个简单的示例,演示如何在Java类中使用`@Builder`注解:

```java
import lombok.Builder;
import lombok.Getter;

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

// 在其他地方使用
Person person = Person.builder()
                .name("Alice")
                .age(30)
                .build();
```

在这个示例中,我们使用`@Builder`注解为`Person`类生成了一个静态的`builder()`方法,可以通过该方法创建`Person`对象,并使用链式调用设置属性的值。这样可以简化对象的创建过程。

 

二、@Builder被编译成了啥

当一个类使用了 @Builder 注解后,在编译过程中会生成一个包含构建者模式代码的静态内部类 Builder。以下是一个简单的示例,演示了一个使用 @Builder 注解的类在编译后生成的构建者模式代码:

原始类:

```java
import lombok.Builder;
import lombok.Data;

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

编译后的代码大致如下:

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

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

    public static PersonBuilder builder() {
        return new PersonBuilder();
    }

    public static class PersonBuilder {
        private String name;
        private int age;

        PersonBuilder() {
        }

        public PersonBuilder name(String name) {
            this.name = name;
            return this;
        }

        public PersonBuilder age(int age) {
            this.age = age;
            return this;
        }

        public Person build() {
            return new Person(name, age);
        }
    }
}
```

在编译后的代码中,可以看到生成了一个名为 PersonBuilder 的静态内部类,该类包含了与原始类 Person 中字段对应的 setter 方法,以及一个 build 方法用于构建 Person 对象。通过调用静态方法 builder() 可以获取到 PersonBuilder 对象,然后可以使用链式调用的方式设置字段的值,最后调用 build() 方法构建出 Person 对象。

 

三、@Builder 容易踩坑的地方

1. 循环引用:假设有两个类 A 和 B,彼此引用对方作为字段,使用 @Builder 可能会导致循环引用。例如:

```java
@Data
@Builder
public class A {
    private B b;
}

@Data
@Builder
public class B {
    private A a;
}

A a = A.builder().b(B.builder().a(a).build()).build();
```

在这种情况下,会导致循环引用,可能会出现栈溢出或无限递归。

2. 默认值设置:在 @Builder 中设置字段的默认值时,要确保正确设置。例如:

```java
@Data
@Builder
public class Person {
    @Builder.Default
    private String name = "Unknown";
}

Person person = Person.builder().build();
System.out.println(person.getName()); // 输出:Unknown
```

3. 继承:默认情况下,@Builder 不会继承父类的字段。如果需要继承父类的字段,可以使用 @SuperBuilder 注解,且父子类都需要加上这个注解。例如:

```java
@Data
@SuperBuilder
public class Parent {
    private String parentField;
}

@Data
@SuperBuilder
public class Child extends Parent {
    private String childField;
}

Child child = Child.builder().parentField("Parent").childField("Child").build();
System.out.println(child.getParentField()); // 输出:Parent
System.out.println(child.getChildField()); // 输出:Child
```

4. 构造函数:@Builder 生成的对象没有公共构造函数。如果需要手动添加构造函数,要注意与 @Builder 的兼容性。例如:

```java
@Data
@Builder
public class ConstructorExample {
    private String field1;
    private String field2;
    
    public ConstructorExample(String field1, String field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

ConstructorExample example = ConstructorExample.builder().field1("Value1").field2("Value2").build();
System.out.println(example.getField1()); // 输出:Value1
System.out.println(example.getField2()); // 输出:Value2
```

 

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0