2016-07-08 2 views
4

Например, у меня есть SimpleCallback классДженерики, типа стирания и статические ткани метод

public class SimpleCallback<T> implements Callback<T> { 

    private SuccessListener<T> successListener; 
    private ErrorListener errorListener; 

    protected SimpleCallback() { 

    } 

    public static <C> SimpleCallback<C> success(SuccessListener<C> listener) { 
     SimpleCallback<C> callback = new SimpleCallback<>(); 
     callback.successListener = listener; 
     return callback; 
    } 

    public SimpleCallback<T> error(ErrorListener errorListener) { 
     this.errorListener = errorListener; 
     return this; 
    } 

    @Override 
    public void onComplete(T result) { 
     notifySuccess(result); 
    } 

    @Override 
    public void onError() { 
     notifyError(); 
    } 

    public interface SuccessListener<T> { 

     void onSuccess(T result); 
    } 

    public interface ErrorListener { 

     void onError(); 
    } 

} 

Теперь я хочу, чтобы использовать эту функцию обратного вызова для получения кошек асинхронными:

SimpleCallback<List<Cat>> callback = SimpleCallback 
      .success(cats -> cats.forEach(Cat::meow)); 

Это нормально, но когда я хочу добавить прослушиватель ошибок, мои кошки становятся необработанными объектами

SimpleCallback<List<Cat>> callback = SimpleCallback 
      .success(cats -> cats.forEach(Cat::meow)) <-- Here cats become objects 
      .error(() -> System.out.println("Cats error")); 

Одно из решений использует явный общий характер pe:

SimpleCallback<List<Cat>> callback = SimpleCallback.<List<Cat>> 
      .success(cats -> cats.forEach(Cat::meow)) 
      .error(() -> System.out.println("Cats error")); 

Но это выглядит немного уродливым. Так какой-нибудь способ создать обратный вызов без явного родового типа?

UPD: Я думаю @Jesper предложил хорошее решение

Другим решением является обеспечение типа аргумента лямбды-выражения в явном виде:

.success((List<Cat> cats) -> cats.forEach(Cat::meow)) 
+2

Другим решением является обеспечение тип аргумента лямбда-выражения в явном виде: '.success ((Список кошек) -> cats.forEach (Cat :: мяу))' – Jesper

+0

Просьба уточнить, в чем проблема является. Если это только факт, что он выглядит незнакомым, то я бы сказал: «Гораздо лучше привыкнуть к нему, чем использовать необработанные типы со всеми недостатками, которые приходят с ним ... – martinhh

+0

@martinhh Вопрос касается вывода типа: почему, когда вы добавляете '.error (...)' после вызова '.success (...)', вывод типа больше не работает (теперь необходимо явно указать тип). – Jesper

ответ

0

Очевидно, что стратегия для стирания общих переменных типа изменения в контексте. Конечно, должны быть правила, как это работает, но я их не знаю, извините.

С практической точки зрения решение, предложенное Jesper, то есть предоставление типа информации в методе успеха, представляется мне совершенно приемлемым.

.success((List<Cat> cats) -> cats.forEach(Cat::meow))

В противном случае можно передать оба Слушателей в одном методе:

public static <C> SimpleCallback<C> create(
    SuccessListener<C> successListener, ErrorListener errorListener) { 
    SimpleCallback<C> callback = new SimpleCallback<>(); 
    callback.successListener = successListener; 
    callback.errorListener = errorListener; 

    return callback; 
} 

и создать обратный вызов в один шаг:

Callback<List<Cat>> callback = SimpleCallback 
     .create(
      cats -> cats.forEach(Cat::meow), 
      () -> System.out.println("Cats error") 
     ); 
0

Короче говоря, нет. От this answer about how the diamond operator functions in Java 1.8 существуют проблемы с выводами типа с любым вызовом вызова с цепочкой. Ваш пример похож, потому что

SimpleCallback<List<Cat>> callback = SimpleCallback 
     .success(cats -> cats.forEach(Cat::meow)); 

является выводя тип C из аргументации в success.

Таким образом, ваши варианты:

  • Явного объявить общий тип
  • Получить именованную ссылку (с явно объявленным общим типом) перед использованием прикованных вызовов

Для примера, я Предпочитаете работать со следующей парадигмой:

Публичный класс SimpleCallback реализует обратный вызов {

private SuccessListener<T> successListener; 
private ErrorListener errorListener; 

protected SimpleCallback() { 

} 

public static <C> SimpleCallback<C> create() { 
    return new SimpleCallback<>(); 
} 

public SimpleCallback<T> withSuccessListener(SuccessListener<T> listener) { 
    this.successListener = listener; 
    return this; 
} 

public SimpleCallback<T> withErrorListener(ErrorListener errorListener) { 
    this.errorListener = errorListener; 
    return this; 
} 

@Override 
public void onComplete(T result) { 
    notifySuccess(result); 
} 

@Override 
public void onError() { 
    notifyError(); 
} 

public interface SuccessListener<T> { 

    void onSuccess(T result); 
} 

public interface ErrorListener { 

    void onError(); 
} 

}

А затем создать в одной строке, добавление и сцепление на следующий.

SimpleCallback<List<Cat>> callback = SimpleCallback.create(); 
callback = callback.success(cats -> cats.forEach(Cat::meow)) 
        .error(() -> System.out.println("Cats error")); 
Смежные вопросы