Dies ist eine Überprüfung der in Java 1.8 eingeführten Funktionsschnittstelle.
Umgebung
Referenz
In diesem Code empfängt die forEach-Methode eine Consumer-Funktionsschnittstelle. Dieses Schreiben ist aber vereinfacht
List<String> list = List.of("a", "b", "c");
list.forEach(System.out::println);
Wenn Sie Java 1.8 oder früher schreiben, ist dies wie folgt.
public class PrintLine implements Consumer<Object> {
@Override
public void accept(Object t) {
System.out.println(t);
}
}
List<String> list = List.of("a", "b", "c");
PrintLine println = new PrintLine();
list.forEach(println);
Wenn Sie eine anonyme Klasse schreiben, sieht diese wie folgt aus.
List<String> list = List.of("a", "b", "c");
list.forEach(new Consumer<Object>() {
@Override
public void accept(Object t) {
System.out.println(t);
}
});
Diese Schreibstile können mithilfe der in Java 1.8 eingeführten Lambda-Ausdrücke vereinfacht werden.
// (1)Wenn Sie den Schreibstil der anonymen Klasse in Lambda-Ausdruck ändern, können Sie ihn so schreiben.
list.forEach((String t) -> {
System.out.println(t);
});
// (2)Der Argumenttyp ist selbsterklärend und kann weggelassen werden.
list.forEach((t) -> {
System.out.println(t);
});
// (3)Wenn es nur ein Argument gibt, das Argument()Kann ausgelassen werden.
list.forEach(t -> {
System.out.println(t);
});
// (4)Wenn der Code im Block eine Zeile ist{}Kann ausgelassen werden. Sie benötigen nicht einmal ein Semikolon in Ihrem Code.
list.forEach(t -> System.out.println(t));
// (5)Abstrakte Methode der funktionalen Schnittstelle (in diesem Fall Consumer).akzeptieren) Unterschrift und
//Wenn die Signaturen der auszuführenden Methoden übereinstimmen, kann sie als Methodenreferenz geschrieben werden.
list.forEach(System.out::println);
Funktionsschnittstellen werden mit "@ FunctionalInterface" kommentiert.
@FunctionalInterface
public interface Consumer<T> {
//...
}
Ein informativer Annotationstyp, der angibt, dass eine Schnittstellentypdeklaration eine funktionale Schnittstelle im Sinne der Java-Sprachspezifikation sein soll. Konzeptionell hat eine funktionale Schnittstelle nur eine abstrakte Methode.
Wie oben zitiert, ist die Bedingung, die die Definition einer funktionalen Schnittstelle erfüllt, dass die Schnittstelle nur eine abstrakte Methode deklariert hat.
Unabhängig davon, ob der Annotationstyp FunctionalInterface in der Schnittstellendeklaration vorhanden ist, behandelt der Compiler jede Schnittstelle, die der Definition einer Funktionsschnittstelle entspricht, als Funktionsschnittstelle.
Wenn diese Bedingung erfüllt ist, wird der Compiler als funktionale Schnittstelle mit oder ohne diese Anmerkung behandelt.
Dieses Paket definiert eine grundlegende Funktionsschnittstelle. Typische Beispiele sind "Consumer", "Function", "Predicate" und "Supplier", und es gibt auch "IntCounsumer" und "IntFunction", die spezielle Versionen davon sind. Es gibt auch funktionale Schnittstellen, die für bestimmte Zwecke außerhalb dieses Pakets implementiert sind.
Parameter eingeben: Eingabetyp T-Operation
Abstrakte Methode
void accept(T t);
BiConsumer Es gibt auch eine funktionale Schnittstelle namens "BiConsumer", die zwei Argumente akzeptiert, nämlich eine Spezialisierung von "Consumer".
Parameter eingeben: T - Art des ersten Operationsarguments U - Typ des zweiten Operationsarguments
Abstrakte Methode
void accept(T t, U u);
java.base : java.util.Iterator<E>
forEach
Eine der häufigsten Methoden zur Verwendung von Consumer ist die forEach-Methode des Iterators.
Iterable.forEach
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
Stichprobe Schreiben Sie seit Java 1.8 nicht wie (1), sondern wie (2) oder (3) mit einem Lambda-Ausdruck. Wenn Sie eine Zeile wie (2) verwenden möchten, müssen Sie sie nicht in einen Block einschließen, und Sie können wie (3) schreiben. Darüber hinaus kann der Code vereinfacht werden, indem er wie in (4) als Methodenreferenz geschrieben wird.
List<String> list = List.of("a", "b", "c");
// (1)
list.forEach(new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}
});
// (2)
list.forEach(s -> {
System.out.println(s);
});
// (3)
list.forEach(s -> System.out.println(s));
// (4)Methodenreferenz
list.forEach(System.out::println);
Parameter eingeben: T-Funktion Eingangstyp R - Funktionsergebnistyp
Abstrakte Methode
R apply(T t);
BiFunction Es gibt auch eine funktionale Schnittstelle namens "BiFunction", die zwei Argumente akzeptiert, nämlich eine Spezialisierung von "Function".
Parameter eingeben: T - Typ des ersten Funktionsarguments U - Typ des zweiten Funktionsarguments R - Funktionsergebnistyp
Abstrakte Methode
R apply(T t, U u);
java.base : java.util.Map<K,V>
computeIfAbsent
Map.computeIfAbsent
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
Stichprobe
Map<String, Integer> map = new HashMap<>();
// (1)
Integer value = map.computeIfAbsent("apple", new Function<String, Integer>(){
@Override
public Integer apply(String t) {
return t.length();
}
});
// (2)
value = map.computeIfAbsent("banana", s -> {
return s.length();
});
// (3)
value = map.computeIfAbsent("cherry", s -> s.length());
// (4)Instanzmethodenreferenz
value = map.computeIfAbsent("durian", String::length);
UnaryOperator<T>
Es handelt sich um eine Funktionstyp-Schnittstelle, die in der Super-Schnittstelle Function
enthält und sich auf Function spezialisiert hat, die denselben Typ wie der Argumenttyp zurückgibt.
Parameter eingeben: T-Operator-Operanden und Ergebnistypen
replaceAll
List.replaceAll
default void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final ListIterator<E> li = this.listIterator();
while (li.hasNext()) {
li.set(operator.apply(li.next()));
}
}
Stichprobe
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");
// (1)
list.replaceAll(new UnaryOperator<String>() {
@Override
public String apply(String t) {
return t.toUpperCase();
}
});
// (2)
list.replaceAll(t -> t.toUpperCase());
// (3)Instanzmethodenreferenz
list.replaceAll(String::toUpperCase);
UnaryOperator.identity
Die UnaryOperator-Schnittstelle verfügt über eine statische Methode namens Identität. (Es ist auch in der Funktionsschnittstelle.)
static <T> UnaryOperator<T> identity() {
return t -> t;
}
Der Code, den Sie häufig als Beispiel für die Verwendung dieser Methode sehen, konvertiert eine Liste in eine Karte, wie unten gezeigt. Diese Konvertierung legt die ID der Item-Klasse im Schlüssel der Map und die Instanz der Item-Klasse im Wert der Map fest. Die Absicht des Codes wird jedoch durch die Verwendung der Identitätsmethode deutlich, die das Eingabeargument zurückgibt.
List<Item> list = new ArrayList<>();
list.add(new Item(1L, "apple"));
list.add(new Item(2L, "banana"));
list.add(new Item(3L, "cherry"));
//Map<Long, Item> fruitIdMap = list.stream()
// .collect(Collectors.toMap(Item::getId, i -> i));
// more than better
Map<Long, Item> fruitIdMap = list.stream()
.collect(Collectors.toMap(Item::getId, UnaryOperator.identity()));
System.out.println(fruitIdMap);
// {1=Item [id=1, name=apple], 2=Item [id=2, name=banana], 3=Item [id=3, name=cherry]}
Parameter eingeben: T-Prädikat-Eingabetyp
Abstrakte Methode
boolean test(T t);
BiPredicate Es gibt auch eine funktionale Schnittstelle namens "BiPredicate", die zwei Argumente akzeptiert, die eine Spezialisierung von "Predicate" sind.
Parameter eingeben: T - Typ des ersten Arguments des Prädikats U - Typ des zweiten Prädikatarguments
Abstrakte Methode
boolean test(T t, U u);
java.base : java.util.Collection<E>
removeIf
Collection.removeIf
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
Stichprobe Dies ist ein Beispiel, bei dem gerade Zahlen aus der Liste entfernt werden. Da removeIf einen Nebeneffekt auf List hat, tritt ein Fehler auf, wenn es sich um eine unveränderliche Liste handelt.
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// (1)
list.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer t) {
return t % 2 == 0;
}
});
// (2)
list.removeIf(t -> {
return t % 2 == 0;
});
// (3)
list.removeIf(t -> t % 2 == 0);
java.base : java.util.Optional<T>
filter
Optional.filter
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
Stichprobe
Optional<Integer> opt = Optional.of(1);
// (1)
Optional<Integer> result = opt.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer t) {
return t % 2 == 0;
}
});
// (2)
result = opt.filter(t -> {
return t % 2 == 0;
});
// (3)
result = opt.filter(t -> t % 2 == 0);
result.ifPresentOrElse(System.out::println, () -> {
System.out.println("it's odd number");
});
// → it's odd number
java.base : java.util.regex.Pattern
asPredicate
Pattern.asPredicate
public Predicate<String> asPredicate() {
return s -> matcher(s).find();
}
Stichprobe
Pattern pattern = Pattern.compile("^\\d+$");
List<String> list = List.of("123", "abc", "456", "78d");
List<String> result = list.stream()
.filter(pattern.asPredicate())
.collect(Collectors.toList());
result.forEach(System.out::println);
// → 123
// → 456
Parameter eingeben: T - Art des von diesem Lieferanten bereitgestellten Ergebnisses
Abstrakte Methode
T get();
java.base : java.util.Optional<T>
orElseGet
Optional.orElseGet
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
Stichprobe
Optional<String> fruit = Optional.ofNullable(null);
// (1)
String result = fruit.orElseGet(new Supplier<String>() {
@Override
public String get() {
return "banana";
}
});
// (2)
result = fruit.orElseGet(() -> {
return "banana";
});
// (3)
result = fruit.orElseGet(() -> "banana");
// (4)Methodenreferenz
result = fruit.orElseGet(SupplierDemo::getDefault);
SupplierDemo
public static String getDefault() {
return "banana";
}
orElseThrow
Optional.orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
Stichprobe
Optional<String> fruit = Optional.ofNullable(null);
// (1)
String result = fruit.orElseThrow(new Supplier<RuntimeException>() {
@Override
public RuntimeException get() {
return new FruitNotFoundException();
}
});
// (2)
result = fruit.orElseThrow(() -> {
return new FruitNotFoundException();
});
// (3)
result = fruit.orElseThrow(() -> new FruitNotFoundException());
// (4)Konstruktorreferenz
result = fruit.orElseThrow(FruitNotFoundException::new);
FruitNotFoundException
class FruitNotFoundException extends RuntimeException {
public FruitNotFoundException() {
super();
}
}
** Beispiel einer Konstruktorreferenz zum Generieren eines Arrays **
List<String> list = List.of("apple", "banana", "cherry", "durian", "elderberry");
// String[] fruits = list.toArray(size -> new String[size]);
// more than better?
String[] fruits = list.toArray(new String[0]);
Der Code zum Konvertieren der obigen Auflistung in ein Array lautet wie folgt, wenn er mit einer Konstruktorreferenz geschrieben wird.
List<String> list = List.of("apple", "banana", "cherry", "durian", "elderberry");
String[] fruits = list.toArray(String[]::new);
java.logging : java.util.logging.Logger
log
Logger.log
public void log(Level level, Supplier<String> msgSupplier) {
if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
doLog(lr);
}
Diese Schnittstelle gibt es seit Version 1.8, sie kann jedoch als Zuweisungsziel für Lambda-Ausdrücke oder Methodenreferenzen verwendet werden, da sie die Anforderungen einer funktionalen Schnittstelle erfüllt.
Abstrakte Methode
boolean accept(File pathname);
listFiles
File.listFiles
public File[] listFiles(FileFilter filter) {
String ss[] = list();
if (ss == null) return null;
ArrayList<File> files = new ArrayList<>();
for (String s : ss) {
File f = new File(s, this);
if ((filter == null) || filter.accept(f))
files.add(f);
}
return files.toArray(new File[files.size()]);
}
Stichprobe
File directory = new File("D:\\temp");
Long limit = 1024L * 1024L * 7L;
File[] overLimitFiles = directory.listFiles(pathname -> pathname.length() > limit);
Abstrakte Methode
void run();
java.base : java.util.Optional<T>
ifPresentOrElse
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
Stichprobe
Optional<String> opt = Optional.ofNullable(null);
opt.ifPresentOrElse(s -> {
System.out.println(s);
},() -> {
System.out.println("null");
});
Abstrakte Methode
boolean matches(Path path);
java.base : java.nio.file.FileSystem
getPathMatcher
FileSystem.getPathMatcher
public abstract PathMatcher getPathMatcher(String syntaxAndPattern);
Stichprobe
Abweichend vom Betreff des Artikels ist der an die Methode "getPathMatcher" übergebene Wert eine Zeichenfolge aus Syntax und Muster, die durch einen Doppelpunkt (:) getrennt ist. Wenn Sie "glob" für die Syntax angeben, können Sie ein einfacheres Muster angeben, das einem regulären Ausdruck für Pattern ähnelt, und wenn Sie "regex" angeben, können Sie einen regulären Ausdruck für Pattern angeben.
FileSystem fileSystem = FileSystems.getDefault();
PathMatcher matcher = fileSystem.getPathMatcher("glob" + ":" + "**/*.java");
Path path = Paths.get("D:", "temp");
try {
Files.walk(path).filter(matcher::matches).forEach(System.out::println);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Zusätzlich zu "compare" deklariert diese Schnittstelle eine abstrakte Methode namens "boolean equals (Object obj)", wie unten angegeben.
Wenn die Schnittstelle eine abstrakte Methode deklariert, die eine der öffentlichen Methoden von java.lang.Object überschreibt, wird dies nicht in der Anzahl der abstrakten Methoden in der Schnittstelle berücksichtigt. Der Grund dafür ist, dass jede Implementierung dieser Schnittstelle Implementierungen von java.lang.Object oder anderswo enthält.
Es erfüllt die Voraussetzungen für eine funktionale Schnittstelle.
Abstrakte Methode
int compare(T o1, T o2);
min
Collections.min
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
if (comp==null)
return (T)min((Collection) coll);
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (comp.compare(next, candidate) < 0)
candidate = next;
}
return candidate;
}
Stichprobe
Dies ist ein Beispiel, das die Priorität und die ID der Jobklasse in aufsteigender Reihenfolge sortiert und den kleinsten Job zurückgibt. Beachten Sie, dass die Sammlung eine große Anzahl von Elementen enthält, wie unten angegeben.
Diese Methode durchläuft die gesamte Sammlung, daher dauert die Zeit proportional zur Größe der Sammlung.
List<Job> list = List.of(
// Id, Priority
new Job(1L, 3),
new Job(2L, 3),
new Job(3L, 2),
new Job(4L, 1),
new Job(5L, 1),
new Job(6L, 2)
);
// (1)
Job minJob = Collections.min(list, new Comparator<Job>() {
@Override
public int compare(Job j1, Job j2) {
if (Objects.equals(j1.getPriority(), j2.getPriority())) {
return Long.compare(j1.getId(), j2.getId());
}
return Integer.compare(j1.getPriority(), j2.getPriority());
}
});
System.out.println(minJob);
// → Job [id=4, priority=1]
// (2)
minJob = Collections.min(list, Comparator.comparing(Job::getPriority).thenComparing(Job::getId));
System.out.println(minJob);
// → Job [id=4, priority=1]
Abstrakte Methode
V call() throws Exception;
submit
ExecutorService.submit
<T> Future<T> submit(Callable<T> task);
Stichprobe
ExecutorService service = Executors.newSingleThreadExecutor();
// (1)
Future<LocalDateTime> future = service.submit(new Callable<LocalDateTime>() {
@Override
public LocalDateTime call() throws Exception {
TimeUnit.SECONDS.sleep(5L);
return LocalDateTime.now();
}
});
/*
// (2)
Future<LocalDateTime> future = service.submit(() -> {
TimeUnit.SECONDS.sleep(5L);
return LocalDateTime.now();
});
*/
LocalDateTime result = future.get();
service.shutdown();
Recommended Posts