funciones ejemplos dominio combinación combinacion java lambda java-8 method-reference

java - dominio - combinacion de funciones ejemplos



Referencia de método Java8 utilizada como objeto Function para combinar funciones (6)

¿Hay alguna manera en Java8 de utilizar una referencia de método como un objeto Function para usar sus métodos, algo así como:

Stream.of("ciao", "hola", "hello") .map(String::length.andThen(n -> n * 2))

Esta pregunta no está relacionada con el Stream , se usa solo como ejemplo, me gustaría tener una respuesta sobre el método de referencia


Debería poder lograr lo que quiere en línea mediante el uso de moldes:

Stream.of("ciao", "hola", "hello") .map(((Function<String, Integer>) String::length).andThen(n -> n * 2))

Solo hay ''sugerencias de tipo'' para el compilador, por lo que en realidad no ''lanzan'' el objeto y no tienen la sobrecarga de un molde real.

Alternativamente, puede usar una variable local para la legibilidad:

Function<String, Integer> fun = String::length Stream.of("ciao", "hola", "hello") .map(fun.andThen(n -> n * 2));

Una tercera forma que puede ser más concisa es con un método de utilidad:

public static <T, X, U> Function<T, U> chain(Function<T, X> fun1, Function<X, U> fun2) { return fun1.andThen(fun2); } Stream.of("ciao", "hola", "hello") .map(chain(String::length, n -> n * 2));

Tenga en cuenta que esto no está probado, por lo tanto, no sé si la inferencia de tipo funciona correctamente en este caso.


Podrías escribir:

Stream.of("ciao", "hola", "hello").map(String::length).map(n -> n * 2);


Puedes escribir un método estático para hacer esto:

import java.util.function.*; class Test { public static void main(String[] args) { Function<String, Integer> function = combine(String::length, n -> n * 2); System.out.println(function.apply("foo")); } public static <T1, T2, T3> Function<T1, T3> combine( Function<T1, T2> first, Function<T2, T3> second) { return first.andThen(second); } }

Luego puede ponerlo en una clase de utilidad e importarlo estáticamente.

Alternativamente, crea un método estático más simple que simplemente devuelve la función que se le da, por el bien del compilador que sabe lo que estás haciendo:

import java.util.function.*; class Test { public static void main(String[] args) { Function<String, Integer> function = asFunction(String::length).andThen(n -> n * 2); System.out.println(function.apply("foo")); } public static <T1, T2> Function<T1, T2> asFunction(Function<T1, T2> function) { return function; } }


Puedes guardarlo en una variable:

Function<String, Integer> toLength = String::length; Stream.of("ciao", "hola", "hello") .map(toLength.andThen(n -> n * 2));

O puede usar un elenco, pero es menos legible, IMO:

Stream.of("ciao", "hola", "hello") .map(((Function<String, Integer>) String::length).andThen(n -> n * 2));


Puedes usar un molde

Stream.of("ciao", "hola", "hello") .map(((Function<String, Integer>) String::length) .andThen(n -> n * 2)) .forEach(System.out::println);

huellas dactilares

8 8 10


También puedes usar

Function.identity().andThen(String::length).andThen(n -> n * 2)

El problema es que String::length no es necesariamente una Function ; puede ajustarse a muchas interfaces funcionales. Debe usarse en un contexto que proporcione el tipo de objetivo, y el contexto podría ser: asignación, invocación de método, conversión.

Si la Function puede proporcionar un método estático solo por el objetivo de escribir a máquina, podríamos hacer

Function.by(String::length).andThen(n->n*2) static <T, R> Function<T, R> by(Function<T, R> f){ return f; }

Por ejemplo, uso esta técnica en una interfaz funcional

static <T> AsyncIterator<T> by(AsyncIterator<T> asyncIterator)

Azúcar de sintaxis para crear un AsyncIterator a partir de una expresión lambda o una referencia de método.

Este método simplemente devuelve el argumento asyncIterator , lo que parece un poco extraño. Explicación:

Como AsyncIterator es una interfaz funcional, se puede crear una instancia mediante una expresión lambda o una referencia de método, en 3 contextos:

// Assignment Context AsyncIterator<ByteBuffer> asyncIter = source::read; asyncIter.forEach(...); // Casting Context ((AsyncIterator<ByteBuffer>)source::read) .forEach(...); // Invocation Context AsyncIterator.by(source::read) .forEach(...);

La tercera opción se ve mejor que las otras dos, y ese es el propósito de este método.