Jakie są odpowiedniki Func i Action w Javie ?
Mam na myśli, zamiast pisać to sam:
public interface Func<TInput, TResult>
{
TResult call(TInput target) throws Exception;
}
public interface Action<T>
{
void call(T target) throws Exception;
}
Odpowiedzi:
W Javie 8 odpowiednikami są odpowiednio interfejsy java.util.function.Function<T, R>i java.util.function.Consumer<T>. Podobnie java.util.function.Predicate<T>jest równoważne z System.Predicate<T>. Jak wspomniano w innym miejscu, są to interfejsy zamiast delegatów.
Powiązane na bok: Obecnie intensywnie opieram się na następującej klasie narzędziowej, aby robić rzeczy związane z rozszerzeniem podobnym do LINQ:
abstract class IterableUtil {
public static <T> Iterable<T> where(Iterable<T> items, Predicate<T> predicate) {
ArrayList<T> result = new ArrayList<T>();
for (T item : items) {
if (predicate.test(item)) {
result.add(item);
}
}
return result;
}
public static <T, R> Iterable<R> select(Iterable<T> items, Function<T, R> func) {
ArrayList<R> result = new ArrayList<R>();
for (T item : items) {
result.add(func.apply(item));
}
return result;
}
}
W przeciwieństwie System.Linq.Enumerable.Where<TSource>i System.Linq.Enumerable.Select<TSource, TResult>LINQ-like metod przedstawiam tutaj nie są leniwi i przed powrotem zbiorów wynikowych do rozmówcy całkowicie przechodzić zbiorów źródłowych. Mimo to uważam je za przydatne do celów czysto syntaktycznych i w razie potrzeby można je rozlenić. Dany
class Widget {
public String name() { /* ... */ }
}
Można wykonać następujące czynności:
List<Widget> widgets = /* ... */;
Iterable<Widget> filteredWidgets = IterableUtil.where(widgets, w -> w.name().startsWith("some-prefix"));
Które wolę od następujących:
List<Widget> widgets = /* ... */;
List<Widget> filteredWidgets = new ArrayList<Widget>();
for (Widget w : widgets) {
if (w.name().startsWith("some-prefix")) {
filteredWidgets.add(w);
}
}
Interfejs wywoływalny jest podobny do Func.
Runnable interfejs jest podobny do Action.
Ogólnie rzecz biorąc, Java używa anonimowych klas wewnętrznych jako zamiennika dla delegatów C #. Na przykład tak dodajesz kod reagujący na naciśnięcie przycisku w GUI:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
...//code that reacts to the action...
}
});
Elegancja z przeciążonych delegatów func (oprócz delegata vs anonimowej klasy emisji) jest to, że wspierają one od 0 do 16 argumentów ( Func<TResult>, Func<T, TResult>, Func<T1, T2, TResult>, itd.)
Niestety w Javie jest to niemożliwe z powodu wymazywania typów. Klasy nie mogą różnić się tylko parametrami typu ogólnego.
Java 8 teraz przynosi w zoo nazwach takich jak BiConsumerdla Action<T, T2>i, ponieważ Java nie pozwala prymitywne argumenty typu, BiIntConsumer. „Zoo” nie jest jednak zbyt duże i nie znam biblioteki, która by je powiększała. Była wspaniała propozycja dla literałów typu funkcji, (int, int) => voidale nie została przyjęta.
Func`1itd. To tylko C #, który odwzorowuje je na tę samą nazwę.
BiConsumerdla Action<T, T2>i, ponieważ Java nie pozwala parametrów typu prymitywne BiIntConsumer. Pojawiła się propozycja literałów typu funkcji, (int, int) => voidale nie została ona przyjęta.
Do Func<T>użytku: java.util.function.Supplier
http://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html
Supplierbyłoby równoważne Func<T>(w przeciwieństwie do Func<T1, T2>) nie Action. An Actionakceptuje żadnych argumentów i nie zwraca wyniku. (Inne wersje Actionakceptują różne liczby argumentów i nie zwracają żadnych wyników).
Func<T>języka Java i omyłkowo zapamiętałem go jako Action<T>. Ups
Action<>: 0 wejść, 0 wyjść. Najlepiej z .andThen(...)funkcjonalnością.
Action<>do 0 wejść i 0 wyjść. Ale pamiętaj, w Javie to tylko interfejsy. Możesz więc stworzyć własny do użytku.
Runnabledla Action<>, chociaż nie jest tak ładny w użyciu, jak nowy funkcjonalny sprzęt Java 8.
Java nie ma koncepcji delegatów. Aby zapoznać się z rozwiązaniem obejścia, zobacz A Java Programmer Looks at C # Delegates :
Chociaż C # ma zestaw możliwości podobnych do Java, dodał kilka nowych i interesujących funkcji. Delegacja to możliwość traktowania metody jako obiektu pierwszej klasy. Delegat AC # jest używany, gdy programiści Java używaliby interfejsu z jedną metodą. W tym artykule omówiono użycie delegatów w języku C # i przedstawiono kod obiektu delegata języka Java, który może wykonywać podobną funkcję. Pobierz kod źródłowy tutaj.
Możesz użyć java.util.Function w ten sposób
Function<Employee, String> f0 = (e) -> e.toString();
Ale jeśli chcesz używać go z więcej niż jednym argumentem (tak jak robi to C # Func), musisz zdefiniować swoją wersję FunctionalInterface w następujący sposób
@FunctionalInterface
public interface Func2Args<T, T1, R> {
R apply(T t, T1 t1);
}
@FunctionalInterface
public interface Func3Args<T,T1,T2,R> {
R apply(T t, T1 t1, T2 t2);
}
Następnie możesz użyć zmiennej liczba argumentów
Func2Args<Employee,Employee,String> f2 = (e, e2) -> e.toString() +
e2.toString();
Func3Args<Employee,Employee,Employee,String> f3 = (e, e2, e3) ->
e.toString() + e2.toString() + e3.toString();
W przypadku starszych wersji niż Java 8
Dla wywołań zwrotnych metod w C #, których użyłem w ten sposób:
public void MyMethod(string par1, string par2, Action<int> callback, Action<int, string> callback2)
{
//Async Code
callback.invoke(1);
callback2.invoke(4, "str");
}
i nazywam to:
utils.MyMethod("par1", "par2", (i) =>
{
//cb result
}, (i, str) =>
{
//cb2 result
});
Stworzyłem małe klasy abstrakcyjne w Javie
package com.example.app.callbacks;
public abstract class Callback1<T> {
public void invoke(T obj) {}
}
package com.example.app.callbacks;
public abstract class Callback2<T, T2> {
public void invoke(T obj, T2 obj2) {}
}
package com.example.app.callbacks;
public abstract class Callback3<T, T2, T3> {
public void invoke(T obj, T2 obj2, T3 obj3) {}
}
...ETC
Metoda Java wygląda następująco:
public void myMethod(String par1, String par2, final Callback1<int> callback, final Callback2<int, String> callback2) {
//Async Code
callback.invoke(1);
callback2.invoke(4, "str");
}
Teraz dzwoniąc w Javie:
utils.myMethod("par1", "par2", new Callback<int>() {
@Override
public void invoke(int obj) {
super.invoke(obj);
//cb result
}
}, new Callback2<int, String>() {
@Override
public void invoke(int obj, String obj2) {
super.invoke(obj, obj2);
//cb2 result
}
});
Działa to również poprzez przekazywanie / ustawianie wywołań zwrotnych do klas, w których chcesz je wywołać, ta sama metoda może być również użyta do tworzenia interfejsów:
package com.example.app.interfaces;
public interface MyInterface<T> {
void makeDo(T obj);
void makeAnotherDo();
}