36

In VB.NET there is the WITH command that lets you omit an object name and only access the methods and properties needed. For example:

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

Is there any such syntax within Java?

Thanks!

Mike Clark
  • 11,769
  • 6
  • 39
  • 43
  • 1
    Thanks for all the responses. I was pretty sure there was no such syntax. Lots of great suggestions for various situations. – Mike Clark Sep 29 '09 at 21:30

8 Answers8

34

No. The best you can do, when the expression is overly long, is to assign it to a local variable with a short name, and use {...} to create a scope:

{
   TypeOfFoo it = foo; // foo could be any lengthy expression
   it.bar();
   it.reset(true);
   myvar = it.getName();
}
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
  • 3
    My understanding of VB isn't great, but I don't think it is doing that. – Tom Hawtin - tackline Sep 29 '09 at 20:50
  • (The equivalent Java would be `foo.bar(); foo.reset(true); String myVar = foo.getName();`.) – Tom Hawtin - tackline Sep 29 '09 at 20:51
  • It would, but it doesn't make much point to do this at all when you already have a variable such as `foo`, which is why I changed the example to involve a more complicated expression. In VB also, `With` is more often used with lengthy expressions. Also, there's no need to declare `myVar` - presumably it's already declared in outer scope. `True` needs correcting though, thanks for pointing that out. – Pavel Minaev Sep 29 '09 at 21:12
16

Perhaps the closest way of doing that in Java is the double brace idiom, during construction.

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

Alternatively, methods that return this can be chained:

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

where bar and reset methods return this.

However, wanting to do this tends to indicate that the object does not have rich enough behaviour. Try refactoring into the called class. Perhaps there is more than one class trying to get out.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 8
    I wouldn't recommend the "double-brace idiom" without pointing out how it works: it's not merely syntactic sugar. It's an anonymous subclass with an instance initializer block inside it. This means that every use of it bloats the code in the jar and in memory with an extra class and means that the run-time class of the object created is a subclass of the named class. – Boann May 21 '14 at 15:26
  • 2
    Anybody who uses that first "idiom" is sacrificing readability and design to do something shorter. If the class was designed for chaining then that certainly can be used (but I cannot downvote those answers separately). – Maarten Bodewes Oct 25 '14 at 11:31
  • @Tom, `with` works with any `obj`, not just `new` ones. – Pacerier May 25 '20 at 01:30
  • {{}} solution is a quick way to memory leaks, and won't work with objects returned by methods. – iirekm Jul 31 '20 at 15:01
16

You can get quite close using Java 8 lambdas, with a drawback of not being able to modify local variables.

Declare this method:

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

So you can use:

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
});

This is also possible using an anonymous class, but not as clean.

Boann
  • 48,794
  • 16
  • 117
  • 146
jpfreire
  • 1,268
  • 16
  • 23
  • 3
    On current compilers and VMs this will load an anonymous class for the block, and instantiate it each time the block runs. Personally I find that too heavyweight, when @PavelMinaev's suggestion doesn't require this. This is an interesting and clever idea though. – Boann May 21 '14 at 15:49
  • 1
    @Boann, lambdas are very common since Java 8. Given that they're always based on anonymous classes, I would assume this kind of instantiation has been optimised and it's not a problem anymore, letting apart nowadasy we have multicore CPUs, giga of RAMs and clouds nowadays, so unless you're developing for small embedded devices or alike, who cares about a few more KBs (or even MBs) and some more ms. But yes, the Pavel's solution is more concise. – zakmck Jan 25 '19 at 19:44
  • This solution is best because if you return T instead of void, you can use it in tree like structures, similarly to Gradle or Groovy builders, with no changes in code. – iirekm Jul 31 '20 at 14:55
  • And performance in recent JVM versions is usually not a problem. Even if it was (maybe on Android), all you need is to optimize for speed only hotspots. For most of code performance is most important. – iirekm Jul 31 '20 at 14:59
6

Some objects allow you to "chain" method invocations, which approaches the syntax you like. For example, often a builder class will return itself from methods so you can do something like this:

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

Each set... method returns this so you can chain the next invocation.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
5

Nope. Java has a policy of avoiding anything that might reduce verbosity.

Well, after writing this it just occurred to me that the closest thing might be static imports, e.g.

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

and now you can do

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

bar();
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
Steve B.
  • 55,454
  • 12
  • 93
  • 132
3

The closest thing to this is static imports that will allow you to call static methods without explicitly specifying the class on which the method exists.

daveb
  • 74,111
  • 6
  • 45
  • 51
2

As already said, you cannot really write the code as this in Java.

Just as a comment, if you are affraid of many copy/paste in the case you need to change the variable name, Eclipse allows you to rename all the references of the variable automatically:

Using ALT+SHIFT+R on the "foo" variable name, you can rename all at once to "myFoo" for instance:

Foo myFoo = new Foo();
myFoo.bar();
myFoo.reset(true);
Boann
  • 48,794
  • 16
  • 117
  • 146
Kloe2378231
  • 1,404
  • 11
  • 12
0

If you have hands on the implementation of Foo, you can use the fluent API concept.

Lets say you have that:

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; }
}

Then you could modify it to obtain this:

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; }
}

And your calling code could look like:

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

Enjoy!

Alex C.
  • 166
  • 3
  • 9