What is the purpose of the default when used in the signature of a method?

Asked

Viewed 1,863 times

5

Within the interface List<E> of Java there is the method replaceAll() the purpose of which is to replace all occurrences of a specified value of a list.

However, in his signature he uses the command default, It’s the first time I’ve seen default being used in signing a method, see your complete signature:

default void replaceAll(UnaryOperator<E> operator)

What is the purpose of default when it is used in the signature of a method as in the above example?

  • boar 8? The default was introduced in this version to allow a method to be implemented in the interface itself, without breaking compatibility with all the methods it implements. You can declare a default method, but it will not be imposed to be implemented in classes that already inherit the interface.

2 answers

6

Java 8 allows calling default methods. They are methods whose implementation may already be available on the interface (which could not happen before). So all classes that implement this interface already get an implementation of the method. Of course the class can override this implementation if you want.

The keyword is only being used to indicate to the compiler that you know what you are doing, that you are implementing an algorithm in the interface aware that this is what you really want, it was no accident.

6


The purpose of a method default is to provide a standard implementation for an interface method in case classes that implement the interface do not implement the method.

Remember that an interface in Java is like a contract. Classes (except the abstract) that implement the interface must implement all interface methods as a contractual obligation, otherwise they do not compile.

In theory, there is no reason to implement a method in an interface, but there are some practical reasons, among which stand out:

Include features without breaking existing code

This is the case of the example quoted in the question, the interface List.

Before the methods default, if you wanted to add a common method to an interface you would potentially break the contract and all classes that implement it would need to be modified.

In the case of List, consider that it is one of the most used Apis and several libraries and systems have their own implementations. This would be an impediment to migrating to the new version of Java until all dependencies and components are also updated.

The main objective of the methods default is to enable the evolution of Apis transparently, without trances, as an "old" code can use a newer API without needing to be updated.

This is especially advantageous when the new method adds some functionality, but is not strictly necessary for the operation of the "old mode".

Of course this does not solve the problem when there is a change in the functioning of an API, in which case the existing methods would need to be modified and methods default are not recommended.

In a simple example, imagine a DAO interface like this:

public interface ClienteDao {
    void incluir(Cliente c);
}

Now, imagine that this DAO has several implementations by several modules of a large system. Different teams are responsible for the different modules which, in turn, are put into production at different times.

In version 2.0 of the system, you add a new method in the interface, but you cannot expect all the other modules to be updated. You could do it like this:

public interface ClienteDao {
    void incluir(Cliente c);
    default void incluir(List<Cliente> clientes) {
        for (Cliente c : clientes) incluir(c);
    }
}

Ready, now the system API is up to date and everything keeps working.

While other teams do not implement the new method, the standard version serves the purposes well. It’s probably not the most optimized thing in the world, but it works.

For a DAO in memory, the standard implementation is probably sufficient. When a team that implements DAO for a particular database updates its module, they can implement an optimized version to include the customers in batch.

Flexibility in code reuse

Reuse of code via inheritance is not usually a good practice, but the reality is that having methods on interfaces enables a special type of multiple inheritance or can even be considered a type of trait.

In Java 6 you could reuse methods from other classes using import static to access static methods as if they were part of the class. But with the methods default from Java 8 you can implement an interface to bring a set of methods to your class.

The advantage of that over the import static is that the methods are part of the class API and it can be used polymorphically.

The advantage of delegating to other classes is that the code gets cleaner.

The advantage over inheritance is that you can "inherit" the methods of various interfaces.

By the way, the whole Java API would be different if methods default had existed longer.

A simple example could be a more flexible generic DAO, usually implemented using an abstract class. If you have any systems experience you know that there are always exceptions and not all Daos need to have all methods. This occurs, for example, in read-only entities.

Example:

public interface GenericDao<T> {
    default Connection getConnection() {
        return DbUtils.getConnection();
    }
}

public interface ReadOnlyDao<T> extends GenericDao<T> {
    T instanciar(ResultSet rs); //específico para cada entidade
    default T recuperar(int id) {
        Connetion c = getConnetion();
        ... executa SQL usando alguma mágica ...
        return instanciar(rs);
    }
    default List<T> listarTodos() {
        ...
    }
}

public interface WriteOnlyDao<T> extends GenericDao<T> {
    void set(PreparedStatement st, T entidade); //coloca os parâmetros da entidade na query
    default void incluir(T entidade) {
        Connetion c = getConnetion();
        ... executa SQL usando alguma mágica ...        
    }
}

public interface DaoCompleto extends ReadOnlyDao, WriteOnlyDao {}

With these implementations, simply implement the interfaces as needed:

public class FeriadosDao implements ReadOnlyDao { ... }
public class LogAcessoDao implements WriteOnlyDao { ... }
public class ClienteDao implements DaoCompleto { ... }

And that’s it, we can incorporate functionality in a granular way, as needed.

  • 1

    Multiple inheritance would solve this problem, right?

  • @jbueno Yes, in a slightly more complicated way.

  • Got it. Very good answer, really.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.