¿Qué son los :: en Java?


¿Vas llevando tiempo programando en Java y de repente encuentras que usan esta notación?

String::toUpperCase

Y te preguntas ¿Ya parece C++? ¿Qué es eso? ¿Cómo funciona ese ::

Aquí explicaremos un poco de qué trata.

Supongamos que tenemos una lista de cadenas y queremos tener otra lista con las mismas cadenas pero con el texto en mayúsculas. La manera común es hacer lo siguiente:

        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        List<String> namesUpper = new ArrayList<>();
        for (String name : names) {
            namesUpper.add(name.toUpperCase());
        }

Sabemos que funciona, con tres instrucciones, en la 11 declaramos la lista de destino, en la 12 comenzamos un bucle, y en la 13 convertimos cada elemento del bucle, lo convertimos a mayúscula con el método String.toUpperCase() (ojo con esto) y lo agregamos a la lista declarada en la línea 11.

Ahora, usando programación funcional que ya está disponible a partir de la versión 8 de Java, podemos hacer lo mismo pero usando una sola línea, así:

        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        List<String> namesUpper = names.stream()
                .map((String name) -> {
                    return name.toUpperCase();
                }).toList();

La línea 13 es similar a la versión anterior: cada iteración del metodo map() tiene como parámetro a name y lo devuelve invocando al método String.toUpperCase(). También se puede resumir así:

        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        List<String> namesUpper = names.stream()
                .map(name -> name.toUpperCase())
                .toList();

El mismo parámetro name es invocado al método toUpperCase() y es devuelto en la función Lambda.

Ahora bien, si ya sabemos que se trata del mismo objeto parámetro del método map ¿para que mencionarlo nuevamente?. Es algo "redundante", si es ese, que solo invoque a SU método. Entonces, aquí viene este anotación curiosa: llamamos a la clase del parámetro y al método que queremos invocar. El compilador ya sabe que se trata del parámetro.

        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        List<String> namesUpper = names.stream()
                .map(String::toUpperCase)
                .toList();

¿Podemos pasar parámetros?

Sí, pero solo uno. Veamos este ejemplo. Consideremos un método que solo imprime la longitud de cada cadena, este método es simple:

    static void printLength(int size) {
        System.out.println("size:" + size); // muy complejo, XD
    }

Ahora, lo que haremos es, tomar la longitud de cada cadena (usando el método String.length) similar al ejemplo anterior, y luego invocamos al método que acabamos de crear. Así que, primero debemos tomar el valor del método, usamos map y luego, por cada ejemplo con - forEach - usamos el método printLength. Primero lo haremos usando parámetros:

public class Ejemplos {

    public static void main(String[] args) {
        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        names.stream()
                .map(name -> name.length())
                .forEach( length -> Ejemplos.printLength(length) );
    }

    static void printLength(int size) {
        System.out.println("size:" + size);
    }

}
  • Línea 10: Extraemos la longitud de cada cadena y se lo pasamos al siguiente método de la llamada funcional.
  • Línea 11: Allí llega como parámetro el valor del método anterior, y allí invocamos al método Ejemplos.printLength(), y como argumento le pasamos el parámetro recibido.

Ahora, lo podemos reducir con la notación especial:

        var names = Arrays.asList("Ann", "Bob", "Carl", "David");
        names.stream()
                .map(String::length)
                .forEach(Ejemplos::printLength);

La línea 10 ya la conocemos, pero la línea 11 es nueva: La notación sabe que el parámetro que está recibiendo (si está llegando) es enviado como argumento al método Ejemplos.printLength.

Esta es la explicación y el uso de la misteriosa notación de los dos puntos ::.

Si te gustó y es útil, comparte que es gratis.

3 Comentarios

Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups


Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/

  1. Hola explicas con ejemplo... pero, mi primera pregunta, ¿Es cómo se llama en java los ::? ... luego lo que logre entender es que se llama a un método de la clase con los dos puntos.... sería clase::Metodo... ¿Puede ser cualquier método de la clase?

    ResponderBorrar
    Respuestas
    1. Hola Carlo, así es, cualquier método PERO que cumpla las siguientes reglas: que sea accesible desde donde se llama (o sea, que cumpla el alcance de public, protected, privated, etc...), que no tenga ningún parámetro o que tenga un solo parámetro que sea del mismo tipo del parámetro que viene de la invocación.
      Eso de la invocación lo mencionaré en un siguiente post sobre "programación funcional en Java, la notación 'Flecha' "

      Borrar
  2. hmm todo ok con los ejemplos pero deberías de centrarte o enfocar mas en los :: osea ser un poco mas directo pero igual se agradece

    ResponderBorrar

Publicar un comentario

Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups


Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/

Artículo Anterior Artículo Siguiente