簡體   English   中英

具有不可變列表的 Lombok Builder?

[英]Lombok Builder with Immutable lists?

我有以下 class 和 Lombok builder:

@Builder(toBuilder = true)
@Data
public class TaskSettings {
    private List<Task> tasks;
    
    public static class TaskSettingBuilder {
        private List<Task> tasks = new ArrayList<>();
        
        public TaskSettingBuilder longLivedTask(Duration duration) {
            // construct long-lived task
            tasks.add(new Task());
            return this;
        }

        public TaskSettingBuilder shortLivedTask(Duration duration) {
            // construct short-lived task
            tasks.add(new Task());
            return this;
        }
    }
}

我有一個自定義構建器,它可以獲取不同類型任務的信息、構造和適當的任務以添加到列表中。 這很好用,但是當我使用toBuilder實現時,它使用原始列表而不是復制它。 因此,如果我向新實例添加一些內容,舊實例將被更新:

TaskSettings ts = TaskSettings.builder()
                .longLivedTask(Duration.ofDays(365))
                .build();
TaskSettings ts2 = ts.toBuilder().shortLivedTask(Duration.ZERO).build();

ts現在將擁有短暫的任務。 我嘗試@Singular注釋,但它生成了接受Task object 而不是讓我構造它的構建器方法。 我知道我可以將任務構建移至Task object 的構建器,但我想將其作為TaskSettings的一部分。 我該如何做到這一點?

使用@Singular或不使用 lombok。 如果您不使用@SingularList沒有什么神奇之處。 這是一個領域。 像任何其他人一樣。

如果您沒有使用@Singular ,並且您的列表對象不是不可變的(您粘貼的代碼段中都是這種情況),那么這個問題可以概括為:

toBuilder()進行淺克隆。但是,鑒於我的對象的字段本身是可變的,我需要一個深層克隆。如何讓 lombok 創建一個深層克隆?”

答案是:Lombok 不這樣做,也沒有簡單的方法讓它這樣做; java 土地上的深度克隆通常是個難題。 沒有很多簡單的方法可以做到這一點。 它要么是大量的跑腿工作(到處寫復制構造函數和clone() impls),要么是hackery(序列化它,然后反序列化它),並且有很多未充分考慮的問題(深度克隆的重點只是為了避免方法調用者弄亂了 state 他們不應該弄亂,因此暗示不可變對象不需要被深度復制,例如)。

因此,向 Project Lombok 提出的功能請求是:“請讓深拷貝成為我可以打開的東西”是有問題的。 我們 lombok 的維護人員將如何滿足該請求?

使用@Singular ,列表本身現在是 lombok 的已知概念,lombok 將相應地采取行動。 它仍然不是深拷貝(即,如果你有一個@Singular List<List<String>> ,除非那些內部列表是不可變的,否則你仍然有麻煩),但列表將(或者如果不是,應該是,文件錯誤!)在您使用toBuilder()添加一些內容時被復制(使用@Singular時獲得的列表是不可變的。如果它沒有更改,則無需復制它)。

我嘗試了@Singular 注釋,但它生成了接受任務 object 而不是讓我構造它的構建器方法。

這聽起來像你在這里如何使用各種 lombok 注釋時犯了一個錯誤,或者可能是 lombok 中的一個錯誤。 你能詳細說明嗎? 因為聽起來答案只是“在你的tasks字段中扔@Singular - 這就是你所需要的。 除非顯然您嘗試過,但結果並未如您所願。

我為此提出了一個新問題,代碼片段顯示了 lombok 最終做了什么以及你想要它做什么。

您應該查看@Builder.ObtainVia https://projectlombok.org/features/Builder

獲得Via 使您能夠創建具有來自其他地方的字段值的實例,例如來自另一個字段或方法的返回

@Builder(toBuilder = true)
@Data
public class TaskSettings {
    @Builder.ObtainVia(method = "initTask") // important
    private List<Task> tasks;

    private List<Task> initTask() {
        return new ArrayList<Task>();
    }
//...
}

class Main {
    public static void main(String[] args) {
        TaskSettings ts = TaskSettings.builder()
                .longLivedTask(Duration.ofDays(365))
                .build();
        System.out.println(ts.getTasks().size()); // 1 
        TaskSettings ts2 = ts.toBuilder().shortLivedTask(Duration.ZERO).build();
        System.out.println(ts.getTasks().size()); // without ObtainVia print 2, with ObtainVia print 1
        System.out.println(ts2.getTasks().size());// without ObtainVia print 2, with ObtainVia print 1
    }
}



暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM