¿Cómo vincular genérica en lambda función entre argumento y el resultado

user3468272:

Me gustaría enlazar tipo genérico del argumento y el resultado de una función. Aquí está un ejemplo sencillo:

private void take(final Function<ListIterator<?>, ?> takeFunction) {
    final ListIterator<String> stringItr = new ArrayList<String>().listIterator();
    final ListIterator<Integer> intItr = new ArrayList<Integer>().listIterator();
    final String string = (String) takeFunction.apply(stringItr);
    final Integer integer = (Integer) takeFunction.apply(intItr);
}

take(itr -> itr.next());
take(itr -> itr.previous());

No quiero hacer fundido porque es obvio que mi función devuelve lo que está en la lista. Me gustaría escribir algo como esto:

private void take(final Function<ListIterator<T>, T> takeFunction) {
    final ListIterator<String> stringItr = new ArrayList<String>().listIterator();
    final ListIterator<Integer> intItr = new ArrayList<Integer>().listIterator();
    final String string = takeFunction.apply(stringItr);
    final Integer integer = takeFunction.apply(intItr);
}

¿Hay alguna manera de lograr eso?

Gracias por adelantado

Editar: Algunas personas les pide un código más real. Intento crear un iterador en una lista de la lista, pero yo quiero que mis sub-listas se cargan solamente cuando se necesita. Me gustaría hacer un método genérico para ser llamado por mi propia ListIterator :: siguiente y anterior.

Aquí es un código más concreto:

    List<List<String>> lists;
    ListIterator<List<String>> curListsIter;
    ListIterator<String> curStringIter;

    @Override
    public String next() {
        return get(
                listIterator -> listIterator.hasNext(),
                listIterator -> listIterator.next(),
                list -> list.listIterator());
    }

    @Override
    public String previous() {
        return get(
                listIterator -> listIterator.hasPrevious(),
                listIterator -> listIterator.previous(),
                list -> list.listIterator(list.size()));
    }

    private String get(final Function<ListIterator<?>, Boolean> has,
            final Function<ListIterator<?>, ?> item,
            final Function<List<String>, ListIterator<String>> iterator) {
        // The current sub list has an item to get
        if (has.apply(curStringIter)) {
            return (String) item.apply(curStringIter);
        }
        // There is a list in the direction
        else if (has.apply(curListsIter)) {
            curStringIter = iterator.apply(
                (List<String>) item.apply(curListsIter));
            return get(has, item, iterator);
        }
        // No more item in sub list nor list
        else {
            throw new NoSuchElementException();
        }
    }

Este código se compila y, potencialmente, funciona, pero me gustaría hacer eso sin ambos elencos en método get (a 'Cadena' y 'Lista').

Holger:

Sobre la base de esta respuesta , que puede resolver su problema real de la siguiente manera:

public class Example {
    List<List<String>> lists;
    ListIterator<List<String>> curListsIter;
    ListIterator<String> curStringIter;

    @Override
    public String next() {
        return get(ListIterator::hasNext, ListIterator::next, List::listIterator);
    }

    @Override
    public String previous() {
        return get(ListIterator::hasPrevious, ListIterator::previous, Example::atEnd);
    }

    private static <T> ListIterator<T> atEnd(List<T> list) {
        return list.listIterator(list.size());
    }

    interface IterFunction {
        <T> T apply(ListIterator<T> t);
    }
    interface GetIterFunction {
        <T> ListIterator<T> apply(List<T> t);
    }
    private String get(Predicate<ListIterator<?>> has,
                       IterFunction item, GetIterFunction getIter) {
        if(curListsIter == null) curListsIter = getIter.apply(lists);
        while(curStringIter == null || !has.test(curStringIter)) {
            // may throw NoSuchElementException
            curStringIter = getIter.apply(item.apply(curListsIter));
        }
        return item.apply(curStringIter);
    }
}

Una interfaz funcional con un método función genérica no puede conseguir implementa a través de la expresión lambda, ya que no hay sintaxis para declarar variables de tipo para ellos. Sin embargo, pueden ser implementados a través de referencias de métodos, que es simple aquí, como la mayoría de las funciones no solo llaman a un método existente.

Sólo la adquisición de un iterador de lista que apunta al final de la lista no es expresable como una sola invocación de un método existente, es por eso que tenemos que crear una nueva aquí, el atEndmétodo. Tenga en cuenta que esto es básicamente lo que hace el compilador de expresiones lambda bajo el capó, la generación de un método sintético que sostiene el cuerpo de la lambda y la creación de un método de referencia a la misma. Pero cuando se declara el método manual, podemos hacer que sea genérica, a diferencia de las expresiones lambda.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=185466&siteId=1
Recomendado
Clasificación