With feature in Java

4

Hi, some time ago I discovered that some programming languages have a feature called with .

For example:  In JS

But in Java I do not know anything like that, does anyone know?

    
asked by anonymous 23.10.2015 / 02:56

2 answers

4

This "feature" is just syntax sugar that modifies the resolution scope including the object passed in with .

Although it can save a bit of typing, using this feature can cause confusion when reading the code when there are ambiguities, so he is discouraged .

There is no direct equivalent in Java, but you can find an equivalent depending on your goal.

Encapsulate the call to the object in the class itself

For example, let's think of an equivalent code:

class ClassePrincipal {
    Document document;

    void metodo1() {
        Context context = document.querySelector("body");
        ...
    }
}

If you want to encapsulate the call without accessing the object document directly, you can do something like this:

class ClassePrincipal {
    Document document;

    void metodo1() {
        Element context = querySelector("body");
        ...
    }

    Element querySelector(String selector) {
        return document.querySelector(selector);
    }
}

Although with one more method, our main method now no longer needs to access the attribute.

Well, for such a simple example this seems ridiculous, but if there are many calls this encapsulation makes code maintenance easy. For example:

class ClassePrincipal {
    Document document;

    void metodo1() {
        Element context = querySelector("body");
        ...
        Element botao = querySelector("#botao");
        ...
        Element menu = querySelector("#menu");
        ...
        Element tabela = querySelector("table");
        ...
    }

    Element querySelector(String selector) {
        return document.querySelector(selector);
    }
}

This example is good especially if you for some reason want to avoid dealing directly with some API, avoiding to couple your code a lot.

An interesting case that occurred to me was to encapsulate click of Selenium because in some circumstances it did not find the element, so it was possible to change the implementation to use an alternative click technique.

Of course this does not work if you need to call several different methods of the object in question, so it is not a one-to-one substitute with with , but it can help in this particular scenario.

Static Import

For static calls, which do not depend on a specific instance of an object, Java still offers import static . Example:

class BibliotecaMatematica {
    public static BigDecimal calcularJurosComposto(BigDecimal valorPresente, BigDecimal taxaDeJuros, int periodos) {
        ...
    }
    public static BigDecimal calcularJurosSimples(BigDecimal valorPresente, BigDecimal taxaDeJuros, int periodos) {
        ...
    }
}

The normal mode of use would be:

class Calculadora {
    void calcular() {
        BigDecimal v1 = BibliotecaMatematica.calcularJurosComposto(...);
        BigDecimal v2 = BibliotecaMatematica.calcularJurosSimples(...);
    }
}

But we could create shortcuts like this:

import static BibliotecaMatematica.*;

class Calculadora {
    void calcular() {
        BigDecimal v1 = calcularJurosComposto(...);
        BigDecimal v2 = calcularJurosSimples(...);
    }
}

It is as if the static methods of the first class were part of the second class.

Initializing objects

In Visual Basic or Delphi I've seen a lot of people use with to initialize objects or registry structures. By example :

With theWindow
    With .InfoLabel
        .Content = "This is a message."
        .Foreground = Brushes.DarkSeaGreen
        .Background = Brushes.LightYellow
    End With

    .Title = "The Form Title"
    .Show()
End With

In Java this is generally not necessary because we prefer patterns like builder or factory method or simply use builders. Example:

public class HtmlElement {
    private String tagName;
    private Map<String,String> attributes;
    private HtmlElement(String tagName, Map<String,String> attributes) {
        this.tagName = tagName;
        this.attributes = attributes;
    }
    public static HtmlElement of(String tagName, Map<String, String> attributes) {
        return new HtmlElement(tagName, attributes);
    }
}

Then the client code looks like this:

HtmlElement table = HtmlElement.of("table", meusAttributos);

Builder pattern and fluent interfaces

Another alternative to initialization is to use the default builder with threaded methods and fluent interfaces. I'm not going to put the implementation here, but you can see this in more detail in my article .

The code to initialize an object would look like this:

new Pedido()
    .para("José")
    .com(1, "Motocicleta")
    .com(2, "Capacete")
    .fechar();  

This is pretty cool to avoid confusion when there are many parameters.

But what about the code boilerplate ?

Implementing the above defaults requires a lot of code. Java is known to need a lot of code to do simple things.

One alternative is to adopt the lombok project. See the code below:

@Data(staticConstructor="of")
public static class Exercise<T> {
    private final String name;
    private final T value;
}

The annotation @Data would generate all the necessary code:

public static class Exercise<T> {
    private final String name;
    private final T value;

    private Exercise(String name, T value) {
        this.name = name;
        this.value = value;
    }

    public static <T> Exercise<T> of(String name, T value) {
        return new Exercise<T>(name, value);
    }

    public String getName() {
        return this.name;
    }

    public T getValue() {
        return this.value;
    }

    @Override public String toString() {
        return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
    }

    protected boolean canEqual(Object other) {
        return other instanceof Exercise;
    }

    @Override public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Exercise)) return false;
        Exercise<?> other = (Exercise<?>) o;
        if (!other.canEqual((Object)this)) return false;
        if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
        if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
        return true;
    }

    @Override public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
        result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
        return result;
    }
}
    
23.10.2015 / 03:37
2

In Java 7, ARM (Automatic Resource Management) was implemented, which allows something very similar:

try (
  FileInputStream in = new FileInputStream("xanadu.txt");
  FileOutputStream out = new FileOutputStream("outagain.txt")
) {
  int c;
  while((c=in.read()) != -1 )
    out.write();
}

See more at documentation

Unfortunately, in previous versions, this feature does not exist.

    
23.10.2015 / 03:16