【问题标题】:Avoid temp variables with constructing items to add to a list通过构造要添加到列表的项目来避免使用临时变量
【发布时间】:2018-01-20 08:16:10
【问题描述】:

Java 8 有很多特性可以让您避免使用临时变量和函数,似乎必须有一种方法可以避免使用这些临时变量来创建此列表:

List<Phone> phones = new ArrayList<>();
Phone p1 = new Phone();
p1.setNumber(this.mainPhoneNumber);
p1.setExtension(this.mainPhoneExt);
p1.setType(this.mainPhoneDesc);
phones.add(p1);
Phone p2 = new Phone();
p2.setNumber(this.secondaryPhoneNumberOne);
p2.setExtension(this.secondaryPhoneExtOne);
p2.setType(this.secondaryPhoneDescOne);
phones.add(p2);
Phone p3 = new Phone();
p3.setNumber(this.secondaryPhoneNumberTwo);
p3.setExtension(this.secondaryPhoneExtTwo);
p3.setType(this.secondaryPhoneDescTwo);
phones.add(p3);

我有一堆丑陋的成员变量需要整理成一个列表。 Phone 对象没有很好的构造函数,我无法更改它。

如何在不定义三个临时对象p1, p2, p3 的情况下从成员变量中创建此列表?

【问题讨论】:

  • 您可以为 Phone 类创建一个构造函数,采用 3 个参数。如果Phone 类中有很多字段,您也可以使用builder pattern 来帮助创建电话的对象。
  • 要删除重复的add() 语句,您需要Java 9 的List.of() 或Guava 的ImmutableList.of()
  • List&lt;Phone&gt; phones = Arrays.asList(p1, p2, p3) 如果您不使用 java 9,也可以使用。
  • 如果 Phonefinal,但实现了一个接口,您可以使用 reflect.Proxy - 带有或(乏味,而不是反对第 3 方代码)没有原始 Phone 的实例班级。 (我想我会因为不得不重复 setter 调用而不是使用其他无用的变量(或数组)而被推迟。)

标签: java algorithm arraylist lambda


【解决方案1】:

你能做这样的事吗?

public Phone phoneMaker(int number, int ext, string description) {
    Phone p = new Phone();
    p.setNumber(number);
    p.setExtension(ext);
    p.setType(description);
    return p;
}
List<Phone> phones = new ArrayList<>();
phones.add(phoneMaker(this.mainPhoneNumber, this.mainPhoneExt, this.mainPhoneDesc));

【讨论】:

    【解决方案2】:

    如果您可以修改 Phone 以使设置器可链接,您可以针对此:

    phones.add(
        new Phone()
            .setNumber(this.mainPhoneNumber)
            .setExtension(this.mainPhoneExt)
            .setType(this.mainPhoneDesc)
    );
    

    如果这不可行,您可以创建一个外部构建器类。使用它看起来像:

    phones.add(
        new PhoneBuilder()
            .number(this.mainPhoneNumber)
            .extension(this.mainPhoneExt)
            .type(this.mainPhoneDesc)
        .build()
    );
    

    实现构建器类很乏味,但很简单。您将所有字段值存储在成员变量中,然后在调用build() 时创建实际的Phone 对象。你会发现自己重复了很多Phone 的方法名称。不用担心,这很正常。

    【讨论】:

    • 我无法更改基础 Phone 类,但我可以创建一个新的私有构建器类。它并没有真正为我节省任何代码行,但它让我感觉好多了,甚至没有少量的副本/意大利面。
    【解决方案3】:

    John Kugelman 和 Teo 向您展示了一些不同的可能性。

    您可以通过

    避免(显式)临时变量
    List<Phone> phones = new ArrayList<>();
    phones.add(new Phone());  // get(0)
    phones.add(new Phone());  // get(1)
    phones.add(new Phone());  // get(2)
    
    phones.get(0).setNumber(this.mainPhoneNumber);
    phones.get(0).setExtension(this.mainPhoneExt);
    phones.get(0).setType(this.mainPhoneDesc);
    
    phones.get(1).setNumber(this.mainPhoneNumberOne);
    phones.get(1).setExtension(this.mainPhoneExtOne);
    phones.get(1).setType(this.mainPhoneDescOne);
    
    phones.get(2).setNumber(this.mainPhoneNumberTwo);
    phones.get(2).setExtension(this.mainPhoneExtTwo);
    phones.get(2).setType(this.mainPhoneDescTwo);
    

    另一种方法是使用匿名类。看起来像

    List<Phone> phones = new ArrayList<>();
    phones.add(new Phone() {   // class
        {                      // initializer  (no this)
             setNumber(mainPhoneNumber);
             setExtension(mainPhoneExt);
             setType(mainPhoneDesc);
        }
    });
    phones.add(new Phone() {
        {
             setNumber(mainPhoneNumberOne);
             setExtension(mainPhoneExtOne);
             setType(mainPhoneDescOne);
        }
    });
    

    警告:您的 this 在初始化程序中不起作用。

    如您所见,有很多不同口味和优缺点的可能性。


    顺便说一句,要实现可链接的设置器或流畅的接口,只需始终返回 this。这是一个例子

    class X {
        private T1 p1;
        private T2 p2;
    
        public X setter1 (T1 p1) {
           this.p1 = p1;
           return this;
        }
    
        public X setter2 (T2 p2) {
           this.p2 = p2;
           return this;
        }
    ...
    }
    

    【讨论】:

    • 我不认为这就是“匿名课程”。使用“new foo() {setSomething()}”语法会创建foo() 的新子类,而不是带有匿名变量的新实例。
    猜你喜欢
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    相关资源
    最近更新 更多