Seit der Veröffentlichung ist ein Jahr vergangen, daher habe ich das Wesentliche des Inhalts nicht geändert und es überprüft und aktualisiert, wobei ich mich darauf konzentriert habe, Erklärungen zur Präsentationsquelle hinzuzufügen.
Es ist mehr als 4 Jahre her, seit Java 8 im März 2014 veröffentlicht wurde, und es wurde von vielen Menschen verwendet, einschließlich Java 9 und Java 10 und höher. Funktionale Programmierung wurde zu einem heißen Thema, als Java 8 veröffentlicht wurde. Heutzutage ist der Begriff funktionale Programmierung bei Systementwicklern allgemein anerkannt und weit verbreitet. Es scheint jedoch, dass die tatsächliche Durchdringung noch weit entfernt ist, da die aktuelle Situation darin besteht, dass wir die Systementwicklungsergebnisse der funktionalen Programmierung nicht häufig sehen. Und wie in Java 8 werden auch vorhandene Sprachen durch die Integration eines funktionalen Programmierstils erweitert. Ich kann nicht vorhersagen, wie der Ablauf in Zukunft aussehen wird, aber ich persönlich spekuliere, dass die Verwendung des funktionalen Programmierstils in vorhandenen Sprachen zum Mainstream wird. Ich denke, dass eine reine funktionale Sprache eine spezielle Verwendung sein wird, und im Java-System wird Scala die Java-Sprache nicht ersetzen. Die funktionale Programmierung scheint sich in einer solchen Situation zu befinden, aber es wird erwartet, dass sie sich in Zukunft auf irgendeine Weise ausbreiten wird. Deshalb habe ich eine allgemeine Umfrage durchgeführt und versucht, die einfache Programmierung in der Java 10-Umgebung zu üben. .. Außerdem habe ich beschlossen, die Lernergebnisse als Memorandum zu veröffentlichen, da ich dachte, dass dies für Interessierte hilfreich sein könnte. Bitte beachten Sie, dass der Inhalt einen subjektiven Teil oder einen Programmstil haben kann, der persönliche Orientierung beinhaltet. Informationen zu Wörtern und Phrasen, die für die Funktionsprogrammierung spezifisch sind, finden Sie in den kurzen Erläuterungen innerhalb des am Ende verstandenen Bereichs. (* Wörter mit Zahlen)
Java 8 fügt die folgenden neuen Funktionen für die Funktionsprogrammierung hinzu:
Bevor ich auf diese Einführungen eingehe, möchte ich kurz erklären, was funktionale Programmierung überhaupt ist.
Im engeren Sinne ist funktionale Programmierung "eine Methode zum Erstellen eines Programms mit Funktionen, die Referenztransparenz (* 9) und keine Nebenwirkungen (* 8) aufweisen", und diese Definition basiert auf einer funktionalen Sprache. Es ist jetzt jedoch möglich, es auch in vorhandenen Sprachen im funktionalen Programmierstil zu implementieren. Hier haben wir uns entschlossen, einen umfassenden Überblick über die funktionale Programmierung zu erhalten, und drei Funktionen aufgelistet.
Ich denke, dass das Erstellen eines Programms mit der oben genannten Methode und dem oben genannten Zweck aus einer breiten Perspektive als funktionale Programmierung erkannt werden kann. Darüber hinaus ist die funktionale Programmierung nicht an Entwicklungsmethoden wie den Entwurfsprozess der Anforderungsanalyse wie objektorientiert gebunden, sondern für den Programmimplementierungsprozess selbst vorgesehen. Um funktionale Programmierung durchzuführen, gibt es solche, die auf Sprachebene unterstützen, wie Haskell und Scala, und solche, die einer vorhandenen Sprache wie Java 8 eine API für funktionale Programmierung hinzufügen. Es wird gesagt, dass Java 8 den Bereich von 1 bis 2 abdecken kann und Haskell und Scala den Bereich von 1 bis 3 abdecken können. Eine Programmiersprache, die Nebenwirkungen fast vermeiden kann, wird auch als rein funktionale Programmiersprache bezeichnet, und unter diesem Gesichtspunkt wird Scalas 3. eher als Quasi-Drei als als reine 3 betrachtet. Es versteht sich jedoch von selbst, dass es vom Projekt abhängt, ob das System mit "Funktionen konfiguriert werden muss, die Nebenwirkungen fast vermeiden". Bei der funktionalen Programmierung wird eine relativ kleine Funktion erstellt und angewendet oder kombiniert, um ein System zu entwickeln, das auf dem Format der deklarativen Programmierung (* 3) basiert. Um Level 3 zu implementieren, ist es daher erforderlich, das Konzept der funktionalen Sprache und der funktionalen Programmierung vollständig zu verstehen und nicht das herkömmliche objektorientierte Programmierverfahren. Darüber hinaus muss im Voraus vollständig verstanden werden, wie gut das Zielproblem mit der funktionalen Programmierung übereinstimmt, z. B. dem verknüpften System, der Plattform-Middleware, dem Plattform-Framework, den zugehörigen akkumulierten Assets und der Entwicklungs- / Management- / Betriebsumgebung. es gibt....
Es scheint von Fall zu Fall einige Situationen für das 4. und 5. Element zu geben, aber es scheint sicher, dass der Programmieraufwand für die zutreffenden Teile reduziert wird. Andererseits besteht der Nachteil darin, dass es theoretisch möglich ist, mit reiner Funktionsprogrammierung zu entwickeln, wenn das Entwicklungssystem mathematisch ausgedrückt werden kann. In Wirklichkeit gibt es jedoch nur wenige solcher Umgebungen, insbesondere die CRUD-Verarbeitung in Geschäftssystemen. Es wird gesagt, dass die Hauptanwendung nicht viel Verdienst hat. Java8 führt neue Mechanismen wie Funktionsschnittstellen, Lambda-Ausdrücke, Streams und Optional ein, um die Funktionsprogrammierung zu unterstützen. Dies ermöglicht es, einige der traditionellen Lehrprogrammierungen in einem funktionalen Programmierstil (deklarative Programmierung) zu schreiben. Und wenn Sie mit diesem Java 8 oder höher funktionale Programmierung durchführen,
Ich denke, es gibt zwei Fälle, aber ich persönlich denke, es ist besser, die Schritte (1) → (2) zu unternehmen, um zu lernen. Beachten Sie, dass die funktionale Programmierung nur unter Java 8 und höher funktioniert. Um mit älteren Java-Versionen wie Java6 und Java7 arbeiten zu können, ist es notwendig, mit der Lehrprogrammierung wie zuvor zu entwickeln, nicht mit der funktionalen Programmierung.
Die wichtigsten neuen und aktualisierten Methoden zur funktionalen Programmierung in Java 8 lauten wie folgt. Diese Methoden werden verwendet, um die Grundfunktionalität der funktionalen Programmierung zu nutzen. Ich denke, es kann so ausgedrückt werden, dass funktionale Programmierung in eine objektorientierte Sprache integriert wird. Sie können die Details jeder dieser Methoden leicht online oder in Büchern herausfinden. Hier geben wir einen Überblick über jede Methode und eine Auswahl typischer Methoden.
・ Funktionsschnittstelle Lambda-Ausdrücke und Methodenreferenzen (* 7) können über die Funktionsschnittstelle verwendet werden. Sie können Ihre eigenen erstellen, es stehen jedoch mehrere Standardfunktionsschnittstellen zur Verfügung.
(): Name der Hauptmethode, Argumenttyp → Rückgabetyp Das Folgende ist ein einfaches Definitions- und Verwendungsbeispiel einer selbst erstellten Funktionstypschnittstelle.
[Schnittstellenbeispiel Verwandte Codebeschreibung]
InterfaceExample
001 public class InterfaceExample{
002 public static void main(String[] args){
003 IHobby hb = (String hobby) -> {
004 return "my hobby : " + hobby;
005 };
006 System.out.println(hb.getHobby("cycling"));
007 }
008 }
009 @FunctionalInterface
010 interface IHobby{
011 public String getHobby(String hobby);
012 }
Unten finden Sie ein einfaches Beispiel für die Verwendung der Funktionsstandard-Funktionsschnittstelle.
[LambdaParameter-bezogene Codebeschreibung]
LambdaParameter
001 package functiontest;
002 import java.io.IOException;
003 import java.util.function.Function;
004 public final class LambdaParameter {
005 public static void main(String[] args) throws IOException {
006 Integer value = 1;
007 Integer res = execute(value, t -> {
008 return getFiveTimes(t);
009 });
010 System.out.println("Ergebnis:" + res);
011 }
/**
*Argument Funktionsschnittstelle(Lambda-Stil)Ausführungsmethode
*/
012 public static <R> R execute(Integer value, Function<Integer, R> fnc) {
013 R rtnval = fnc.apply(value);
014 return rtnval;
015 }
/**
*Methode zur Ausführung der Betonbearbeitung(Multiplizieren Sie den Wert mit 5)
*/
016 public static Integer getFiveTimes(Integer value) {
017 return value * 5;
018 }
019 }
· Karte Der vorhandenen Map-Klasse wurden auch neue Methoden hinzugefügt. Die wichtigsten hinzugefügten Methoden sind forEach, replaceAll, computeIfAbsent, computeIfPresent, compute und merge.
Unten finden Sie ein einfaches Beispiel. (k: Kartenschlüssel v: Kartenwert p: Argumentwertschlüssel: Angegebener Schlüssel)
[Kartenbezogene Codebeschreibung] Der Map-Typ ist String, String. ・ ForEach (001): Gibt alle Elemente der Karte im Format [Schlüssel: Wert] aus. ・ ReplaceAll (002 ~): Ersetzen Sie die Werte aller Kartenelemente durch null → [Schlüssel] und ungleich Null → [Schlüssel + erste 2 Wertzeichen]. ・ ComputeIfAbsent (008 ~): a. Wenn der Schlüssel im Kartenschlüssel vorhanden ist Der Wert wird nicht aktualisiert und der Wert ist der Rückgabewert. b. Wenn der Schlüssel vorhanden ist und der Wert null ist Der Wert wird auf [Schlüssel + "-Addition"] aktualisiert und dieser Wert ist der Rückgabewert. c. Wenn es im Schlüssel nicht vorhanden ist Fügen Sie einen Wert mit Schlüssel und Wert [Schlüssel + "-Addition"] zur Zuordnung hinzu, und dieser Wert ist der Rückgabewert. ・ ComputeIfPresent (011 ~): a. Wenn der Schlüssel im Kartenschlüssel vorhanden ist Der Wert wird auf [Schlüssel + Wert + "-Addition"] aktualisiert und dieser Wert ist der Rückgabewert. b. Wenn der Schlüssel vorhanden ist und der Wert null ist Der Wert wird nicht aktualisiert und null ist der Rückgabewert. c. Wenn es im Schlüssel nicht vorhanden ist Der Wert wird nicht hinzugefügt oder aktualisiert, und null ist der Rückgabewert. ・ Berechnen (014 ~): a. Wenn der Schlüssel im Kartenschlüssel vorhanden ist Der Wert wird auf [Schlüssel + Wert + "-Addition"] aktualisiert und dieser Wert ist der Rückgabewert. b. Wenn der Schlüssel vorhanden ist und der Wert null ist Der Wert wird auf [Schlüssel + Wert (null) + "-Addition"] aktualisiert, und dieser Wert ist der Rückgabewert. c. Wenn es im Schlüssel nicht vorhanden ist Fügen Sie das Element (Schlüssel, [Schlüssel + Wert (null) + "-Addition"]) zur Karte hinzu, und dieser Wert ist der Rückgabewert. ・ Zusammenführen (017 ~): a. Wenn der Schlüssel im Kartenschlüssel vorhanden ist Der Wert wird auf [Wert + "-add"] aktualisiert und dieser Wert ist der Rückgabewert. b. Wenn der Schlüssel vorhanden ist und der Wert null ist Der Wert wird auf ["-add"] aktualisiert (wobei Nullwerte ignoriert werden) und dieser Wert ist der Rückgabewert. c. Wenn es im Schlüssel nicht vorhanden ist Fügen Sie das Element (Schlüssel, ["-add"]) (ignorieren Sie den Nullwert) zur Karte hinzu, und dieser Wert ist der Rückgabewert.
MapMethod
forEach:
001 map.forEach((k, v) -> System.out.println(k + ":" + v));
replaceAll:
002 map.replaceAll((k, v) -> {
003 if (null == v) {
004 return k;
005 }
006 return k + v.substring(0, 2);
007 });
computeIfAbsent:
008 map.computeIfAbsent(key, k -> {
009 return k + "-addition";
010 });
computeIfPresent:
011 map.computeIfPresent(key, (k, v) -> {
012 return k + v + "-addition";
013 });
compute:
014 map.compute(key, (k, v) -> {
015 return k + v + "-addition";
016 });
merge:
017 map.merge(key, "-add", (v, p) -> v + p);
· Aufführen Der vorhandenen List-Klasse wurden auch neue Methoden hinzugefügt. Die wichtigsten hinzugefügten Methoden sind forEach, removeIf, replaceAll, stream und parallelStream.
Unten finden Sie ein einfaches Beispiel. (v: Listenwert Wert: externer Wert)
[Liste der zugehörigen Codebeschreibungen] Der Listentyp ist String. ・ ForEach (001): Gibt Werte für alle Elemente der Liste aus. ・ RemoveIf (002 ~): Die Liste enthält einen bestimmten Wert: Das entsprechende Element wird gelöscht und true zurückgegeben. b. Der angegebene Wert ist null: Das entsprechende Element wird nicht gelöscht und false wird zurückgegeben. c. Kein angegebener Wert: Das Element wird nicht gelöscht und false wird zurückgegeben. ・ ReplaceAll (008 ~): Nicht-Null-Wert für alle Elemente: Auf die ersten 2 Zeichen des Werts aktualisiert. b. Nullwert für alle Elemente: Der Wert wird nicht aktualisiert. ・ Sortieren (014): a. Die Sortierung nach natürlicher Reihenfolge / Null-Maximalwert wird für alle Elemente durchgeführt. ・ Stream (015): a. Holen Sie sich den Stream der Liste. ・ ParallelStream (016): a. Holen Sie sich einen parallelen Listenstrom.
ListMethod
forEach:
001 list.forEach(v -> System.out.println(v));
removeIf:
002 list.removeIf(v -> {
003 if (null == v) {
004 return false;
005 }
006 return v.equals(value);
007 });
replaceAll:
008 list.replaceAll(v -> {
009 if (null == v) {
010 return v;
011 }
012 return v.substring(0, 2);
013 });
sort:
014 list.sort(Comparator.nullsLast(Comparator.naturalOrder()));
stream:
015 Stream sm = list.stream();
parallelStream:
016 Stream sm = list.parallelStream();
・ Stream-API Es ist eine API für die Verarbeitung von Arrays und Sammlungen und kann für die Datenverarbeitung wie die Aggregation von Werten verwendet werden. Stream-Methoden werden je nach Operationsinhalt in zwei Typen eingeteilt, einen für die Zwischenverarbeitung und einen für die Beendigungsverarbeitung. Führen Sie die Beendigungsverarbeitungsmethode über 0 oder mehr Zwischenverarbeitungsmethoden aus. Eine primitive Stream-API ist ebenfalls verfügbar. Methode zur Zwischenverarbeitung asDoubleStream、asLongStream、boxed、distinct、filter、flatMap、flatMapToDouble、flatMapToInt、flatMapToLong、limit、map、mapToDouble、mapToInt、mapToLong、mapToObj、onClose、parallel、peek、sequential、skip、sorted、unordered Das Folgende ist eine kurze Beschreibung typischer Methoden.
Unten finden Sie ein einfaches Beispiel. (Stream: Stream-Instanz v: Stream-Werteliste: Externe Liste numlimit: Externer Wert)
[Beschreibung des Stream-bezogenen Codes (Zwischenverarbeitung)]
Der Stream-Typ ist Integer.
・ Filter (001 ~):
a. Stream Extrahiert ein Vielfaches von 3 für alle Elemente und kehrt mit Stream
StreamMethod1
filter:
001 stream.filter(v -> {
002 return (v%3) == 0;
003 });
map:
004 list.stream().map(Paths::get);
flatMap:
005 list.stream().flatMap(v -> {
006 String[] array = new String[Integer.parseInt(v.substring(1))];
007 Arrays.fill(array, "abc" + v);
008 return Stream.of(array);
009 }).collect(Collectors.toList());
distinct:
010 stream.distinct();
sorted:
011 stream.sorted();
limit:
012 stream.limit(numlimit);
Kündigungsmethode allMatch、anyMatch、average、collect、count、findAny、findFirst、forEach、forEachOrdered、iterator、max、min、noneMatch、reduce、spliterator、sum、summaryStatistics、toArray Nachfolgend finden Sie eine kurze Beschreibung typischer Methoden.
Unten finden Sie ein einfaches Beispiel. (Stream: Stream-Instanz v: Stream-Wert-Array: Externes Array AC: Akkumulator)
[Beschreibung des Stream-bezogenen Codes (Terminierungsverarbeitung)]
・ AllMatch (001 ~):
Der Stream wird unter der Bedingung "Alle Übereinstimmungen" (0
StreamMethod2
allMatch:
001 stream.allMatch(v -> {
002 if ((0 < v) && (10 > v)) {
003 return true;
004 }
005 return false;
006 });
anyMatch:
007 stream.anyMatch(v -> {
008 return v.equals(5);
009 });
collect:(Es gibt mehrere Typen)
010 //Beispiel 1:Arrays.stream(array).collect(Collectors.toList());
011 //Beispiel 2:list.stream().collect(StringBuilder::new, (b, v) -> b.append(v), (b1, b2) -> b1.append(b2));
//1. Argument:Ergebnisspeicherobjektgenerierung, 2. Argument:Speichern Sie das dritte Argument des Stream-Werts:Objektverknüpfung
count:
012 list.stream().count();
reduce:(Es gibt mehrere Typen)
013 list.stream().reduce((ac, v) -> ac + v);
max:
014 list.stream().max(Comparator.naturalOrder());
min:
015 list.stream().min(Comparator.naturalOrder());
toArray:
016 Object[] array = list.stream().toArray();
filter+forEach:
017 stream.filter(v -> {
018 return v%3 == 0;
019 }).forEach(System.out::println);
· Optional Optional ist eine Klasse, die einen Wert umschließt. Sie können nach Nullen und Werten suchen. Optional.ofNullable, Optional.empty (), opt.isPresent (), ...
Es gibt viele Beispiele für mehrere Zeilen im Netz und in Büchern, aber hier werde ich ein Beispiel für ein Level mit einer bestimmten Funktion vorstellen. Funktionsprogrammierung sollte jedoch nicht so durchgeführt werden, sondern wird aus der Perspektive der Referenzcodierung für ein rudimentäres Verständnis erstellt. Funktionen sind Produktinventarverwaltung und bestehen aus zwei Klassen, der Hauptklasse und der FunctionStock-Klasse. Beachten Sie, dass die FunctionStock-Klasse formal so viele API-Verwendungsbeispiele wie möglich enthält, sodass die funktionale Programmierung auch dann durchgeführt wird, wenn sie nicht benötigt wird. Klassenübersicht StockMain: Die Hauptklasse der Bestandsverwaltung. Wir machen keine funktionale Programmierung. FunctionStock: Eine Klasse, die tatsächlich Inventar verarbeitet. Ich mache funktionale Programmierung mit mehreren Methoden. IStock: Schnittstelle der Inventarverarbeitungsklasse. IStockExecuter: Homebrew-Funktionsschnittstelle für die Bestandsverarbeitung. Die detaillierte Funktion und den Kommentar der Methodenübersicht finden Sie im Kommentar der Hauptklasse. Die Art der von der Markierung ☆ verwendeten Funktionsprogrammierung wird beschrieben.
[StockMain-bezogene Codebeschreibung] Karten, in denen die Anzahl der Bestände und Zubehörkonfigurationen gespeichert sind, sind in den Jahren 013 bis 014 definiert. Von 025 bis 036 werden 6 Artikel und die anfängliche Lagermenge eingestellt. CD und Magazin haben Zubehör. Die spezifische Verarbeitung wird in 016 bis 022 eingestellt. Das Buch definiert zwei Kaufprozesse und einen Verkaufsprozess. Magazin definiert einen Verkaufsprozess. Schließlich wird der Ausgabeprozess der Inventarliste definiert. 037 bis 046 führen den Kaufvorgang mit der Lagermethode aus. 047 bis 056 führen die Verkaufsabwicklung mit der Verkaufsmethode aus. Die Menge ist negativ. 057 bis 066 geben die Lagermenge des angegebenen Produkts nach der Methode get aus. 067 bis 076 geben die Inventarliste der Produkte mit der Methode getList aus. Die Einkaufsabwicklung, die Verkaufsabwicklung, die Ausgabe der Bestandsmenge und die Ausgabe der Bestandsliste werden alle von der Ausführungsmethode von FunctionStock ausgeführt.
StockMain.java
001 package stocksample;
002 import java.util.Arrays;
003 import java.util.List;
004 import java.util.Map;
005 import java.util.TreeMap;
/**
*Hauptklasse der Bestandsführung
*Funktion: Einkaufsprozess(stock), Verkaufsabwicklung(sale), Inventarprüfungsverarbeitung(get), Verarbeitung der Inventarlistenausgabe(getList)
* (): Methodenname
*Bestandsdatenverarbeitungsformat: Methodenname(Produktname,Menge)
*Zubehör für jedes Produkt(Mehrfach möglich, aber jede Menge ist auf eins begrenzt)Wird beigefügt und das Inventar des Zubehörs wird ebenfalls verwaltet.
*Kaufprozess: Erhöhen Sie die Anzahl der angegebenen Produkte auf Lager um die Anzahl der Käufe. Wenn das angegebene Produkt nicht registriert ist, wird auch das Produkt registriert.
*Verkaufsabwicklung: Reduzieren Sie die Anzahl der angegebenen Produkte auf Lager um die Anzahl der verkauften Produkte. Wenn jedoch kein Lagerbestand einschließlich Zubehör vorhanden ist, wird die Verarbeitung gestoppt.
*Bestandsprüfungsverarbeitung: Gibt die Anzahl der angegebenen Produkte auf Lager aus.
*Bestandslisten-Ausgabeverarbeitung: Gibt die Anzahl der Bestände aller Produkte aus. Die Zubehörliste wird ebenfalls ausgegeben.
*Behandlung von Fehlern: Gibt eine Fehlermeldung aus, wenn sie auftritt, und bricht die nachfolgende Verarbeitung ab.
*/
006 public class StockMain {
007 private static Map<String, Integer> stockMap;
008 private static Map<String, List<String>> subStockMap;
009 private static IStock stockObject;
010 private static final boolean funcOption = true; //JDK8-Version
//private static final boolean funcOption = false; //JDK6,JDK7-Version
011 public static void main(String[] args) {
012 System.out.println("**start**");
//
//Stellen Sie den anfänglichen Kartenwert ein
013 stockMap = new TreeMap<String, Integer>();
014 subStockMap = new TreeMap<String, List<String>>();
015 setInitialMap();
//
//Bestandsdatenverarbeitung
016 stock("book", 1);
017 stock("book", 2);
018 sale("book", 2);
019 get("book");
020 sale("magazine", 2);
021 get("magazine");
022 getList();
//
023 System.out.println("**end**");
024 }
/**
*Methode zum Festlegen des anfänglichen Kartenwerts
*/
025 private static void setInitialMap() {
026 List<String> cdlist = Arrays.asList("posterA", "posterB", "posterC");
027 subStockMap.put("cd", cdlist);
028 List<String> mglist = Arrays.asList("bagA");
029 subStockMap.put("magazine", mglist);
030 stockMap.put("cd", 3);
031 stockMap.put("magazine", 3);
032 stockMap.put("posterA", 3);
033 stockMap.put("posterB", 3);
034 stockMap.put("posterC", 3);
035 stockMap.put("bagA", 3);
036 }
/**
*Methode zur Durchführung des Kaufprozesses
*/
037 private static void stock(String productName, int quantity) {
038 if (funcOption) {
039 stockObject = new FunctionStock(productName, quantity, "add");
040 } else {
041 stockObject = new Stock(productName, quantity, "add");
042 }
043 setMap();
044 int result = stockObject.execute();
045 if (0 > result) System.exit(result);
046 }
/**
*Methode zur Abwicklung von Verkäufen
*/
047 private static void sale(String productName, int quantity) {
048 if (funcOption) {
049 stockObject = new FunctionStock(productName, -quantity, "add");
050 } else {
051 stockObject = new Stock(productName, -quantity, "add");
052 }
053 setMap();
054 int result = stockObject.execute();
055 if (0 > result) System.exit(result);
056 }
/**
*Methode zur Ausgabe der Lagermenge des angegebenen Produkts
*/
057 private static void get(String productName) {
058 if (funcOption) {
059 stockObject = new FunctionStock(productName, "get");
060 } else {
061 stockObject = new Stock(productName, "get");
062 }
063 setMap();
064 int result = stockObject.execute();
065 if (0 > result) System.exit(result);
066 }
/**
*Methode zur Ausgabe der Inventarliste
*/
067 private static void getList() {
068 if (funcOption) {
069 stockObject = new FunctionStock("getlist");
070 } else {
071 stockObject = new Stock("getlist");
072 }
073 setMap();
074 int result = stockObject.execute();
075 if (0 > result) System.exit(result);
076 }
/**
*Methode zum Festlegen der Zuordnung zum Lagerobjekt
*/
077 private static void setMap() {
078 stockObject.setStockMap(stockMap);
079 stockObject.setSubStockMap(subStockMap);
080 }
081 }
[Funktionsbestandsbezogene Codebeschreibung] Für 028 bis 042 werden Produktname, Menge und Typ im Konstruktor in 013 bis 014 festgelegt. Typ stellt die Art der Verarbeitung dar, und Hinzufügen, Delname, Get und Getlist können angegeben werden. ・ Methode ausführen Die angegebenen Bestandsdaten werden zur Bestätigung um 044 ausgegeben. Überprüfung der angegebenen Bestandsdaten von 045 bis 048. Überprüfen Sie die Inventardaten mit der Methode getDataCheckFunction (). Get (), rufen Sie die Ergebniszeichenfolge ab, konvertieren Sie sie mit Optional.ofNullable in Optional, führen Sie mit ifPresent eine optionale Nullbeurteilung durch und zeigen Sie bei einem Fehler einen Fehler mit outputErrorMessage an Ich werde. In 052 wird die Bestandsdatenverarbeitung durch die Methode executeStock (). Execute () (selbst erstellte Funktionsschnittstelle IStockExecuter) ausgeführt, und das Verarbeitungsergebnis wird im optionalen generischen Typ Integer gespeichert. Um 053 wird die Fehlermeldung bei der Bestandsdatenverarbeitung von der Methode getErrorKeyFunction () generiert. Die Methode (result) anwenden und von outputErrorMessage ausgeben. -GetDataCheckFunction-Methode 066 bis 078 definiert die Implementierung einer Funktionsschnittstelle (generischer Lieferantentyp: String), die Inventardaten überprüft (Nullprüfung usw.). ・ ExecuteStock-Methode 079 bis 096 definieren eine funktionale Schnittstellenimplementierung (von IStockExecuter), die Inventardaten verarbeitet (Verarbeitungstypen: add, delname, get, getlist). Es ruft updateStock (). Get (), deleteStockName (). Get (), getStock (). Get (), outputStockList (getStockList (). Get ()), outputSubStockList () auf. ・ UpdateStock-Methode 097 bis 126 definieren die Implementierung einer funktionalen Schnittstelle (generischer Lieferantentyp Optional), die die Anzahl der Bestände aktualisiert. Die Bestandsmenge wird mit der Methode addToStockMap (). Apply (・ ・) aktualisiert. ・ AddToStockMap-Methode Definiert die Implementierung einer Funktionstypschnittstelle (generischer BiFunction-Typ: String, Integer, Optional), die speziell die Anzahl der Bestände in 127 bis 138 aktualisiert. Die Berechnungsmethode von Map wird verwendet, um die Anzahl der Bestände zu erhöhen oder zu verringern. -DeleteStockName-Methode 139 bis 147 definieren die Implementierung einer funktionalen Schnittstelle (generischer Lieferantentyp: Optional), die zu lagernde Artikel löscht (Bestandsdaten). Die Entfernungsmethode von Map wird verwendet, um die Artikel auf Lager zu löschen. ・ GetStock-Methode 148 bis 154 definieren die Implementierung einer funktionalen Schnittstelle (generischer Lieferantentyp: Optional), die die Anzahl der Bestände eines bestimmten Artikels erfasst. Die Bestandsmenge wird mit der getOrDefault-Methode von Map erfasst. ・ GetStockList-Methode Definiert die Implementierung einer Funktionsschnittstelle (generischer Lieferantentyp: String), die die Bestandsmengenliste in 155 bis 166 abruft. Die Inventarliste wird mit der forEach-Methode von Map erstellt. -GetErrorKeyFunction-Methode 167 bis 175 definieren die Implementierung einer Funktionstypschnittstelle (generischer Funktionstyp: Optional, Zeichenfolge), die das Ergebnis der Bestandsverarbeitung überprüft. Die optionale Zuordnungsmethode (Errindex) definiert die Nachrichtengenerierung im Fehlerfall. -OutputSubStockList-Methode Eine Liste des Zubehörs wird von 191 bis 204 ausgegeben. Die zusätzlichen Ausgabeinformationen für ein bestimmtes Element werden von der Erfassungsmethode nach dem Konvertieren von Liste zu Stream generiert. -OutputErrorMessage-Methode Für messageKey werden Fehlermeldungen von 205 bis 220 ausgegeben. Nach dem Konvertieren von messageKey in Optional wird von der Map-Methode eine Fehlermeldung generiert.
FunctionStock.java
001 package stocksample;
002 import java.util.Arrays;
003 import java.util.List;
004 import java.util.Map;
005 import java.util.Optional;
006 import java.util.function.BiFunction;
007 import java.util.function.Function;
008 import java.util.function.Supplier;
/**
*Bestandsverwaltungsklasse
*/
009 public final class FunctionStock implements IStock {
010 private String productName;
011 private int quantity;
012 private Map<String, Integer> stockMap;
013 private Map<String, List<String>> subStockMap;
014 private String type;
015 private String errorKey;
016 private String errorProductName;
017 private final List<String> typeList = Arrays.asList("add", "delname", "get");
018 private final List<String> errorKeyList = Arrays.asList("zerostock,subzerostock", "noname", "noname");
019 private final List<String> errorMessageKeyList= Arrays.asList(
020 "nullname", "noname", "number", "zerostock", "subzerostock","keyerror");
021 private final List<String> errorMessageList= Arrays.asList(
022 "★ Der Produktname ist nicht angegeben.",
023 "★ Der in der Inventarliste angegebene Produktname existiert nicht.",
024 "★ Die Menge ist nicht angegeben.",
025 "★ Der Lagerbestand wird unter Null liegen.<%p1%> <%p2%>Stücke",
026 "★ Die Menge des auf Lager befindlichen Zubehörs ist kleiner als Null.<%p1%> <%p2%>Stücke",
027 "★ Der Schlüssel ist abnormal.");
/**
*Konstrukteur
*/
028 public FunctionStock(String productName, int quantity, String type) {
029 this.productName = productName;
030 this.quantity = quantity;
031 this.type = type;
032 };
/**
*Konstrukteur
*/
033 public FunctionStock(String productName, String type) {
034 this.productName = productName;
035 this.quantity = 0;
036 this.type = type;
037 };
/**
*Konstrukteur
*/
038 public FunctionStock(String type) {
039 this.productName = "";
040 this.quantity = 0;
041 this.type = type;
042 };
/**
*Methode zur Verarbeitung von Inventardaten
*☆ Verwenden Sie die optionalen Methoden Nullable, ifPresent und orElse
*☆ Verwenden Sie die Apply-Methode der Funktionsschnittstelle
*/
043 public int execute() {
//Ausgabe von Inventardaten
044 outputData();
//Bestandsdatenprüfung
045 Optional.ofNullable(getDataCheckFunction().get()).ifPresent(ekey -> {
046 outputErrorMessage(ekey);
047 errorKey = ekey;
048 });
049 if (null != errorKey) {
050 return -1;
051 }
//Bestandsdatenverarbeitung
052 Optional<Integer> result = executeStock().execute();
//Fehlerausgabe
053 outputErrorMessage(getErrorKeyFunction().apply(result));
054 return result.orElse(-1);
055 }
/**
*Methode zur Ausgabe von Inventardaten
*/
056 private void outputData() {
057 StringBuilder sb = new StringBuilder();
058 sb.append("Daten verarbeiten:");
059 sb.append(productName);
060 sb.append(",");
061 sb.append(quantity);
062 sb.append(",");
063 sb.append(type);
064 System.out.println(sb.toString());
065 }
/**
*Methode zur Überprüfung der Inventardaten
*☆ Verwendet Funktionsschnittstelle Lieferant
*/
066 private Supplier<String> getDataCheckFunction() {
067 return () -> {
068 if (null == productName || (!"getlist".equals(type) && "".equals(productName))) {
069 return "nullname";
070 }
071 if ("add".equals(type)) {
072 if (0 == quantity) {
073 return "number";
074 }
075 }
076 return null;
077 };
078 }
/**
*Methode zur Verarbeitung von Inventardaten
*☆ Verwenden Sie die selbst erstellte Funktionstyp-Schnittstelle IStockExecuter
*☆ Verwenden Sie die optionale leere Methode
*/
079 private IStockExecuter executeStock() {
080 return () -> {
081 Optional<Integer> result = Optional.empty();
082 if ("add".equals(type)) {
083 result = updateStock().get();
084 } else if ("delname".equals(type)) {
085 result = deleteStockName().get();
086 } else if ("get".equals(type)) {
087 result = getStock().get();
088 } else if ("getlist".equals(type)) {
089 outputStockList(getStockList().get());
090 outputSubStockList();
091 } else {
092 errorKey = "keyerror";
093 }
094 return result;
095 };
096 }
/**
*Methode zum Aktualisieren der Bestandsmenge(Kann erhöht oder verringert werden)
*☆ Verwendet Funktionsschnittstelle Lieferant
*☆ Verwenden Sie die Apply-Methode der Funktionsschnittstelle BiFunction
*☆ Verwenden Sie Optionale Methode
*☆ Verwenden Sie die List forEach-Methode
*☆ Verwenden Sie die getOrDefault-Methode von Map
*/
097 private Supplier<Optional<Integer>> updateStock() {
098 return () -> {
099 if (0 > addToStockMap().apply(productName, quantity).get()) {
100 addToStockMap().apply(productName, -quantity);
101 return Optional.of(-1);
102 }
103 if (0 > quantity) {
104 List<String> slist = subStockMap.get(productName);
105 if (null != slist) {
106 slist.forEach(v -> {
107 if (null != errorProductName) return;
108 int substock = stockMap.getOrDefault(v, -1);
109 if (-1 == substock || 0 > (substock + quantity)) {
110 errorProductName = v;
111 }
112 });
113 if (null == errorProductName) {
114 slist.forEach(v -> {
115 addToStockMap().apply(v, quantity);
116 });
117 }
118 }
119 if (null != errorProductName) {
120 addToStockMap().apply(productName, -quantity);
121 return Optional.of(-2);
122 }
123 }
124 return Optional.of(0);
125 };
126 }
/**
*Methode zum Aktualisieren des Lagerwerts des Produkts
*☆ Verwendet die Funktionsschnittstelle BiFunction
*☆ Verwenden Sie die Berechnungsmethode von Map
*☆ Verwenden Sie Optionale Methode
*/
127 private BiFunction<String, Integer, Optional<Integer>> addToStockMap() {
128 return (pname, qty) -> {
129 int addedValue = stockMap.compute(pname, (k, v) -> {
130 if (null == v) v = 0;
131 return v + qty;
132 });
133 if (0 > addedValue) {
134 return Optional.of(-1);
135 }
136 return Optional.of(addedValue);
137 };
138 }
/**
*Methode zum Löschen von Bestandsdaten von Waren
*☆ Verwendet Funktionsschnittstelle Lieferant
*☆ Verwenden Sie Optional von Nullable, isPresent und von Methoden
*/
139 private Supplier<Optional<Integer>> deleteStockName() {
140 return () -> {
141 int result = -1;
142 if (Optional.ofNullable(stockMap.remove(productName)).isPresent()) {
143 result = 0;
144 }
145 return Optional.of(result);
146 };
147 }
/**
*Methode, um die Anzahl der Aktien zu erhalten
*☆ Verwendet Funktionsschnittstelle Lieferant
*☆ Verwenden Sie die getOrDefault-Methode von Map
*☆ Verwenden Sie Optionale Methode
*/
148 private Supplier<Optional<Integer>> getStock() {
149 return () -> {
150 int result = stockMap.getOrDefault(productName, -1);
151 outputNumberStock(result);
152 return Optional.of(result);
153 };
154 }
/**
*Methode zum Generieren einer Inventarliste
*☆ Verwendet Funktionsschnittstelle Lieferant
*☆ Verwenden Sie die Map forEach-Methode
*/
155 private Supplier<String> getStockList() {
156 return () -> {
157 StringBuilder sb = new StringBuilder();
158 stockMap.forEach((k, v) -> {
159 sb.append(k);
160 sb.append(":");
161 sb.append(v);
162 sb.append("\n");
163 });
164 return sb.toString().substring(0, sb.toString().length()-1);
165 };
166 }
/**
*Methode zur Überprüfung des Ergebnisses der Bestandsverarbeitung
*☆ Funktionstyp-Schnittstelle Funktion verwenden
*☆ Verwenden Sie die optionalen Methoden map und orElse
*/
167 private Function<Optional<Integer>, String> getErrorKeyFunction() {
168 return errindex -> {
169 Optional<String> opkey = errindex.map(eindex -> {
170 if (0 <= eindex) return "";
171 return errorKeyList.get(typeList.indexOf(type)).split(",")[Math.abs(eindex)-1];
172 });
173 return opkey.orElse("");
174 };
175 }
/**
*Methode zur Ausgabe der Anzahl der Bestände
*/
176 private void outputNumberStock(int result) {
177 if (-1 < result) {
178 StringBuilder sb = new StringBuilder();
179 sb.append("☆ Lagermenge des angegebenen Lagernamens:");
180 sb.append(productName);
181 sb.append(" ");
182 sb.append(result);
183 sb.append("Stücke");
184 System.out.println(sb.toString());
185 }
186 }
/**
*Methode zur Ausgabe der Inventarliste
*/
187 private void outputStockList(String list) {
188 System.out.println("☆ Inventarliste");
189 System.out.println(list);
190 }
/**
*Methode zur Ausgabe der Zubehörliste
*☆ Verwenden Sie die Methoden Map forEach und getOrDefault
*☆ Verwenden Sie die Stream-Methode von List
*☆ Verwenden Sie die Erfassungsmethode von Stream
*/
191 private void outputSubStockList() {
192 System.out.println("☆ Zubehörliste");
193 stockMap.forEach((k, v) -> {
194 List<String> list = subStockMap.getOrDefault(k, null);
195 if (null != list) {
196 StringBuilder sb = list.stream().collect(StringBuilder::new, (ssb, adname) -> {
197 ssb.append(adname);
198 ssb.append(", ");
199 }, (ba, bb) -> {ba.append(bb);});
200 String str = k + " : " + sb.toString();
201 System.out.println(str.substring(0, str.length()-2));
202 }
203 });
204 }
/**
*Methode zur Ausgabe einer Fehlermeldung
*☆ Verwenden Sie die Option Optional ofNullable und Map
*/
205 private void outputErrorMessage(String messageKey) {
206 if ("".equals(messageKey)) return;
207 Optional<String> mes = Optional.ofNullable(messageKey).map(m -> {
208 String messtr = errorMessageList.get(errorMessageKeyList.indexOf(m));
209 if (-1 < messtr.indexOf("<%p")) {
210 String pname = productName;
211 if (null != errorProductName) {
212 pname = errorProductName;
213 }
214 messtr = messtr.replace("<%p1%>", pname).replace("<%p2%>", String.valueOf(stockMap.get(pname)));
215 }
216 return messtr;
217 });
218 System.out.println(mes.get());
219 System.out.println("★ Die Verarbeitung wurde abgebrochen.");
220 }
221 public void setStockMap(Map<String, Integer> stockMap) {
222 this.stockMap = stockMap;
223 }
224 public void setSubStockMap(Map<String, List<String>> subStockMap) {
225 this.subStockMap = subStockMap;
226 }
227 }
IStock.java
001 package stocksample;
002 import java.util.List;
003 import java.util.Map;
004 public interface IStock {
005 public int execute();
006 public void setStockMap(Map<String, Integer> stockMap);
007 public void setSubStockMap(Map<String, List<String>> subStockMap);
008 }
IStockExecuter.java
001 package stocksample;
002 import java.util.Optional;
003 @FunctionalInterface
004 public interface IStockExecuter {
005 public abstract Optional<Integer> execute();
006 }
Im Folgenden finden Sie eine kurze Erläuterung der Begriffe zur Funktionsprogrammierung, die häufig im Internet vorkommen. Da es schwierig ist, die Monade zu verstehen, habe ich eine zusätzliche Erklärung hinzugefügt.
[Zusätzliche Erklärung von Monad] Lassen Sie uns eine zusätzliche Erklärung zu Monad aus Programmsicht schreiben. "Monade" ist ein allgemeiner Begriff für verschiedene Arten von Monaden (Monadeninstanzen) und eine Typklasse in Haskell (funktionale Sprache). Die Standardmonaden sind: Vielleicht Monade, Listenmonade, Identitätsmonade, Entweder Monade, Staatsmonade, IO-Monade, Schriftsteller-Monade, Lesermonade, ... (In Haskell wird es auch als Vielleicht-Typ, Listentyp, ... bezeichnet.) Um eine Monade zu werden, müssen Sie die folgenden drei Bedingungen erfüllen. Wenn diese Bedingung erfüllt ist, kann sie als Monade bezeichnet werden. (1) Erhalten Sie ein Typargument. (2) Es kann durch Return and Bind (>> = Operator) betrieben werden. return ist eine Funktion, um einen Wert in die Monade zu setzen. bind ist ein Operator zum Übergeben des Werts der Monade an die Funktion. Er wird als monad >> -Funktion beschrieben und der Rückgabewert wird in die Monade eingefügt. (3) Erfüllen Sie die festgelegten Monadenregeln. Wenn Sie die Bedingungen erfüllen, handelt es sich um eine Monade, sodass Sie Ihre eigenen erstellen können, indem Sie die folgenden Schritte ausführen. (1) Definieren Sie den Typ als Monade. (2) Definieren Sie eine Instanz von Monad. (Beinhaltet Return- und Bind-Implementierungen.) Der Hauptzweck dieser Monade ist Monadenwert >> = Monadentypfunktion 1 >> = Monadentypfunktion 2 >> = Monadentypfunktion 3 ---> Monadenwert abrufen Ist in der Lage zu sein, Funktionen kontinuierlich auszuführen, wie. In Monad ist es auch möglich, beim Kombinieren eine Verarbeitung hinzuzufügen. Monadenwert: Der Wert, den die Monade hat. Monadentypfunktion: Eine Funktion, die einen Monadenwert empfängt und das Verarbeitungsergebnis als Monadenwert zurückgibt. Insbesondere können Monaden wie folgt verwendet werden. (Es ist nur ein Beispiel. Die Sprache ist Haskell.)
*> let addOne x = Just (x + 1) - Definition der Funktion addOne (Just bedeutet, dass es sich um den Wert von Maybe monad handelt) *> let addTwo x = Just (x + 2) - Definition der Funktion addTwo *> return 2 >> = addOne >> = addTwo --Kann 2 in die Monade einfügen und die Funktionen addOne und addTwo ausführen
Ergebnis: Nur 5 Dies ist ein Beispiel für die Verwendung der Vielleicht-Monade zum Kombinieren von zwei Funktionen, wobei >> = der Operator zum Kombinieren ist. Die endgültige Rückgabe 2 >> = addOne >> = addTwo kann auch im folgenden Format angegeben werden. do return 2 addOne addTwo Ich denke, die folgenden Schritte sind gut, um Monad besser zu verstehen.
Ich habe Haskell übrigens noch nie benutzt.
Monadendefinition
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> y
fail :: String -> m a
fail msg = error msg
das ist alles. Vielen Dank für das Lesen bis zum Ende.
Recommended Posts