使用@Builder(toBuilder = true)而不是setter会产生开销吗?

时间:2019-04-04 12:39:12

标签: java performance immutability setter builder

我一直在努力使我的代码完全不可变,根本不使用setter。

当我需要更新对象,dto或实体时,我使用@Builder(toBuilder = true)而不是二传手。

public Car updateCar(final String id) {
    final Car existing = carRepository.getById(id);
    final Car.CarBuilder builder = existing.toBuilder().make("Mercedes-Benz");
    if (anyCondition) {
        builder.status("READY");
    }
    final Car updatedCar = builder.build();
    return carRepository.save(updatedCar);
}

我想问你,从性能的角度来看,不是创建一个已实例化的对象而不是为它设置值,而是创建一个新对象,这真的很糟糕吗?

也许在上面的代码中,它并不重要,但我还可能需要更改集合中所有对象的一个​​字段,因此空间复杂度是线性的。

您更喜欢哪种方法:setter或toBuilder?

P.S .:上面的代码段只是为了更好地理解我如何利用toBuilder

1 个答案:

答案 0 :(得分:2)

  

我想问你,表演真的很糟糕吗?   观点,而不是将值设置为已经   实例化的对象,我创建一个新对象?

您是在问我们自己,还是您自己,是错的问题。
对于这种简单的数据载体类,您实际上不必担心性能
基准测试(请参见JMH)。

但是从纯粹的理论观点来看,唯一的开销是创建另一个对象(内存中的大小取决于其成员的布局),这是传输原始值/引用的附加步骤生成器实例到生成的实例(也许还有更多的GC工作?我什至不考虑)。
因此,需要更多的CPU周期。

还要查看Immutables,看看有多少人和公司正在使用它,并问自己是否对于您的简单用例是否应该考虑问这个问题。


参加这堂课

public class Car {
    private String maker;
    private int year;
    private int kms;

    // Getter - setters
}

大小约为16 + 4 + 4 + 4 = 28字节。
现在,使用诸如

的构建器
public class CarBuilder {
    private String maker;
    private int year;
    private int kms;

    public CarBuilder setMaker(final String maker) {
        this.maker = maker;
        return this;
    }

    public CarBuilder setYear(final int year) {
        this.year = year;
        return this;
    }

    public CarBuilder setKms(final int kms) {
        this.kms = kms;
        return this;
    }

    public Car createCar() {
        return new Car(maker, year, kms);
    }
}

大小仍然约为16 + 4 + 4 + 4 = 28字节。

这意味着您至少要使用构建器将 double 个字节用于堆中,以仅用于类
但是,您需要考虑的是Java是基于引用的。这意味着所有创建的对象的 pointers 都将被简单地复制到产生的Car实例中。这些对象在内存中仍然是唯一的。


编辑后,也许您想做的是对象池化
在这种情况下,请考虑Apache Commons Pool