【问题标题】:WITH statement in JavaJava 中的 WITH 语句
【发布时间】:2009-09-29 20:38:27
【问题描述】:

在 VB.NET 中有 WITH 命令可以让您省略对象名称而只访问所需的方法和属性。例如:

With foo
   .bar()
   .reset(true)
   myVar = .getName()
End With

Java中有这样的语法吗?

谢谢!

【问题讨论】:

  • 感谢所有回复。我很确定没有这样的语法。针对各种情况有很多很棒的建议。

标签: java vb.net syntax syntactic-sugar


【解决方案1】:

没有。当表达式过长时,您可以做的最好的事情是将其分配给具有短名称的局部变量,并使用{...} 创建一个范围:

{
   TypeOfFoo it = foo; // foo could be any lengthy expression
   it.bar();
   it.reset(true);
   myvar = it.getName();
}

【讨论】:

  • 我对VB的理解不是很好,但我认为它不会那么做。
  • (等效的 Java 将是 foo.bar(); foo.reset(true); String myVar = foo.getName();。)
  • 它会,但是当你已经有一个变量比如foo时,这样做根本没有多大意义,这就是为什么我改变这个例子来涉及一个更复杂的表达式。同样在 VB 中,With 更常用于冗长的表达式。此外,没有必要声明 myVar - 大概它已经在外部范围内声明了。 True 需要更正,感谢您指出这一点。
【解决方案2】:

也许在 Java 中最接近的方法是在构造过程中使用双大括号。

Foo foo = new Foo() {{
    bar();
    reset(true);
    myVar = getName(); // Note though outer local variables must be final.
}};

或者,返回this 的方法可以被链接:

myName =
    foo
        .bar()
        .reset(true)
        .getName();

其中bar 和reset 方法返回this。

然而,想要这样做往往表明对象没有足够丰富的行为。尝试重构到被调用的类。可能不止一个班级想出去。

【讨论】:

  • 如果不指出它是如何工作的,我不会推荐“双大括号成语”:它不仅仅是语法糖。它是一个匿名子类,里面有一个实例初始化程序块。这意味着每次使用它都会使 jar 和内存中的代码膨胀,并带有一个额外的类,并且意味着创建的对象的运行时类是命名类的子类。
  • 任何使用第一个“成语”的人都在牺牲可读性和设计来做一些更短的事情。如果该类是为链接而设计的,那么当然可以使用(但我不能单独对这些答案投反对票)。
  • @Tom, with 适用于任何obj,而不仅仅是new。
  • {{}} 解决方案是一种快速解决内存泄漏的方法,并且不适用于方法返回的对象。
【解决方案3】:

使用 Java 8 lambdas 可以非常接近,但缺点是无法修改局部变量。

声明这个方法:

static <T> void with(T obj, Consumer<T> c) {
    c.accept(obj);
}

所以你可以使用:

Window fooBarWindow = new Window(null);

String mcHammer = "Can't Touch This";

with(fooBarWindow, w -> {
     w.setAlwaysOnTop(true);
     w.setBackground(Color.yellow);
     w.setLocation(300, 300);

     w.setTitle(mcHammer); // can read local variables
     //mcHammer = "Stop!"; // won't compile - can't modify local variables
});

这也可以使用匿名类,但不是那么干净。

【讨论】:

  • 在当前的编译器和虚拟机上,这将为块加载一个匿名类,并在每次块运行时实例化它。当@PavelMinaev 的建议不需要这个时,我个人觉得这太重了。不过,这是一个有趣而聪明的想法。
  • @Boann,lambdas 自 Java 8 以来非常普遍。鉴于它们始终基于匿名类,我认为这种实例化已经过优化,不再是问题,让我们先不管我们现在拥有多核 CPU、千兆 RAM 和云,所以除非您正在为小型嵌入式设备或类似设备进行开发,否则谁关心更多 KB(甚至 MB)和更多 ms。但是,是的,Pavel 的解决方案更简洁。
  • 此解决方案最好,因为如果您返回 T 而不是 void,您可以在树状结构中使用它,类似于 Gradle 或 Groovy 构建器,无需更改代码。
  • 在最近的 JVM 版本中性能通常不是问题。即使它是(也许在 Android 上),你所需要的只是优化速度热点。对于大多数代码而言,性能是最重要的。
【解决方案4】:

某些对象允许您“链接”方法调用,这接近您喜欢的语法。例如,构建器类通常会从方法中返回自身,因此您可以执行以下操作:

MyObject b = new MyBuilder().setFoo(5).setBar(6).setBaz("garply!").build();

每个set... 方法都返回this,因此您可以链接下一个调用。

【讨论】:

    【解决方案5】:

    不。 Java 的政策是避免任何可能减少冗长的事情。

    好吧,写完这篇文章后,我突然想到最接近的可能是静态导入,例如

    package a.b.c.d;
    public class Foo {
       public static void bar() {
          ...
       }
    }
    

    现在你可以做

    package d.e.f;
    import static a.b.c.d.Foo.*;
    
    bar();
    

    【讨论】:

    • 冗长?我猜他们在创建条件运算符 (?:) 时搞砸了。 VB 往往比 Java 更冗长。
    • “不。Java 有避免任何可能减少冗长的事情的政策。” - 有趣的绞刑架幽默。
    • @niloderoock,但它也是真的。谷歌“java样板战争”
    【解决方案6】:

    与此最接近的是静态导入,它允许您调用静态方法而无需显式指定方法所在的类。

    【讨论】:

      【解决方案7】:

      如前所述,您不能真正用 Java 编写这样的代码。

      就像注释一样,如果您害怕在需要更改变量名称的情况下进行多次复制/粘贴,Eclipse 允许您自动重命名变量的所有引用:

      在“foo”变量名上使用 ALT+SHIFT+R,您可以一次性重命名为“myFoo” :

      Foo myFoo = new Foo();
      myFoo.bar();
      myFoo.reset(true);
      

      【讨论】:

        【解决方案8】:

        如果你有 Foo 的实现,你可以使用 fluent API 的概念。

        假设你有这个:

        public class Foo {
            private String a;
            private String b;
            public void setA(String a) { this.a = a; }
            public void setB(String b) { this.b = b; }
            public String getName() { return this.a + " " + this.b; }
        }
        

        然后你可以修改它以获得这个:

        public class Foo {
            private String a;
            private String b;
            public Foo setA(String a) { this.a = a; return this; }
            public Foo setB(String b) { this.b = b; return this; }
            public String getName() { return this.a + " " + this.b; }
        }
        

        您的调用代码可能如下所示:

        String name = new Foo().setA("foo")
                               .setB("bar")
                               .getName();
        

        享受吧!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-26
          • 2014-05-21
          • 1970-01-01
          • 2014-08-06
          • 2012-09-27
          • 2020-02-29
          • 2011-08-07
          相关资源
          最近更新 更多