用Java链接的方法

Jon*_*lor 39 java methods method-chaining chaining

虽然我早些时候在这里回答了一些问题,但最近我一直在做的一些工作中,我一直在想为什么Java不支持对其内置类进行方法链接.

Car例如,如果我要创建一个类,我可以通过reutrning 而不是void来使它可链接,this如下所示:

public class Car {
    private String make;        

    public Car setMake(String make) {
        this.make = make;
        return this;
    }   
}
Run Code Online (Sandbox Code Playgroud)

内置库不倾向于以这种方式做事有什么特别的原因吗?方法链是否存在缺点?

我可能忽略了一些可以解释缺少方法链接的东西,但是默认情况下返回void的任何setter方法应该返回对此的引用(至少在我看来应该如此).这将使以下情况变得更加清洁.

container.add((new JLabel("label text")).setMaximumSize(new Dimension(100,200)));
Run Code Online (Sandbox Code Playgroud)

而不是更长时间的啰嗦:注意:如果你愿意,它不会阻止你以这种方式编码.

JLabel label = new JLabel("label text");
label.setMaximumSize(new Dimension(100,200));
container.add(label);
Run Code Online (Sandbox Code Playgroud)

我非常有兴趣听到这个决定背后的原因,如果我不得不猜测会有与此相关的开销,所以只应在需要时使用.

Lou*_*man 34

呃.可以在两个方向上进行可读性论证 - 这样的事情就是试图将过多的东西放在一条线上.

但老实说,我怀疑这是出于历史原因:当Swing正在开发时,普遍的"链接"行为并没有真正变得流行或众所周知.您可能会争辩说它应该在以后添加,但是这样的事情往往会产生二进制不兼容性以及Sun/Oracle历来非常谨慎的其他问题.

更新的JDK库 - 例如参见ByteBuffer一个主要的,众所周知的例子 - 已经提供了链接行为等,它是有意义的.

  • 我相信这是正确的答案.作为一个历史记录,许多Java的创始人都有Smalltalk的背景.Smalltalk没有很多"然后返回这个"方法,因为它有一个语法结构,用于分号形式的方法链接.也许这影响了Java的设计者.即使他们没有包含链接运算符. (4认同)
  • @JonTaylor"很遗憾他们不更新摇摆":他们有点做,它被称为[Java Fx 2](http://www.oracle.com/technetwork/java/javafx/overview/faq-1446554.html #6). (2认同)

Tom*_*icz 19

我能想到的另一个原因是性能,或者更确切地说:不要为不使用的东西买单.return this在每个方法都不是很昂贵之后,但仍然需要很少的额外CPU周期和一个CPU注册表.

甚至有一个想法是return this为每个声明void返回值的方法添加隐式但它被拒绝了.

  • @LouisWasserman是的,我指的是*甚至有一个想法是在每个声明void返回值的方法中添加隐式返回这个[...]*也许"syntactic"是错误的单词,"编译时间"更好.我的意思是表达式`<expr> .y()`的值,其中`y`是一个void方法,将是`<expr>`的值.换句话说,取消引用`void`值会使编译器在解除引用链中回顾,直到找到非`void`表达式.因此,这不会产生任何性能影响(可能除了编译之外),并且在字节代码中不可见. (4认同)
  • 我不相信性能是完全避开这种方法的理由.如果您分析您的程序并发现链接是真正的,真正的瓶颈,那么请确保:不要使用它.但如果你还没有这样做,那么声称性能原因就是过早优化**.** (4认同)
  • 请解释,哦,匿名downvoter. (3认同)
  • TL; DR:编译器会让我们使用`void`方法,就像它返回`this`一样,尽管它实际上不会.(它不需要返回`this`,因为我们已经知道,在呼叫站点,它认为是'this`.) (3认同)
  • JIT是否会认真地对此进行优化?至少,对于每个方法都足够短的内联,它应该...... (2认同)
  • @LouisWasserman:+1,但听起来好像很多工作.JIT必须检查对方法的所有调用,并确保它们都没有实际使用返回值.加载每个类后,必须重复此检查过程.还要记住反思性调用. (2认同)
  • 关于隐式`return this`,可以实现为纯粹的语法结构 - 例如,从`x.setFoo(1).setBar(2)`到`{<type> tmp = x; tmp.setFoo(1); tmp.setBar(2);}`.(我不是downvoter.) (2认同)
  • @gustafc:那不可能是_purely_句法; 你只能用自己返回`void`的方法来做.呃.在大多数情况下,我希望JIT能够优化它.(特别是,我注意到`ByteBuffer` - 看起来非常精心设计用于高性能工作 - 使用链接语法...) (2认同)

biz*_*lop 9

虽然我们可以猜测真正的原因,但其中一个可能是严格来说它不是非常OO.

如果将方法视为表示建模世界的操作的操作,则方法链接并不真正适合该图片.

另一个原因可能是当您尝试覆盖链式方法时可能发生的混乱.想象一下这种情况:

class Foo {
   Foo chainedMethod() {...}
}

class Bar extends Foo {
   Foo chainedMethod() {...} //had to return Foo for Java versions < 1.5
   void doStuff();
}
Run Code Online (Sandbox Code Playgroud)

因此,当您尝试这样做时new Bar().chainedMethod().doStuff(),它将无法编译.而且((Bar)new Bar().chainedMethod()).doStuff()看起来不太好,是吗:)

  • 我看到你来自哪里,但我觉得这就像要求一个带有奶酪和番茄酱的**汉堡**而不是一个带有奶酪的**汉堡和同样的汉堡再次启用番茄酱**.是的,我的例子很愚蠢,但我认为传达了我的观点(可能). (4认同)
  • 我不确定我是否同意,我会说你只是一次执行多项行动. (2认同)
  • @JonTaylor OO解决方案是组合`setCheeseAndKetchup()`动作.我不得不说我不一定同意这个观点,但强硬OO是基于严格模拟现实生活活动的方法原则. (2认同)
  • 我不是说我同意它.我更喜欢实用的解决方案,而且每一个能说明你必须做什么和不得做的理论都可以超越它实际可用的范围.对OO的过于严格的解释可能是一个真正的痛苦,但尝试用方法链接做一切并且没有一点常识可能同样痛苦. (2认同)