Un an s'est écoulé depuis la publication, je n'ai donc pas changé l'essence du contenu, je l'ai revu et mis à jour en me concentrant sur l'ajout d'explications sur la source de la présentation.
Cela fait plus de 4 ans que Java 8 a été publié en mars 2014, et il a été utilisé par de nombreuses personnes, notamment Java 9 et Java 10 et versions ultérieures. La programmation fonctionnelle est devenue un sujet brûlant lors de la sortie de Java 8. De nos jours, le terme programmation fonctionnelle est généralement reconnu et répandu parmi les développeurs de systèmes. Cependant, il semble que la pénétration réelle soit encore loin, car la situation actuelle est que nous ne voyons pas fréquemment les résultats du développement du système de la programmation fonctionnelle. Et, comme avec Java 8, les langages existants sont également améliorés en incorporant un style de programmation fonctionnel. Je ne peux pas prédire à quoi ressemblera le flux à l'avenir, mais je suppose personnellement que l'utilisation du style de programmation fonctionnelle dans les langages existants deviendra le courant dominant. Je pense qu'un langage fonctionnel pur sera un usage spécialisé, et dans le système Java, Scala ne remplacera pas le langage Java. La programmation fonctionnelle semble être dans une telle situation, mais on s'attend à ce qu'elle se propage d'une manière ou d'une autre à l'avenir, j'ai donc fait une étude générale et essayé de pratiquer la programmation simple dans l'environnement Java 10. .. De plus, j'ai décidé d'afficher les résultats d'apprentissage sous forme de mémorandum, pensant que cela pourrait être utile pour ceux qui sont intéressés. Veuillez noter que le contenu peut avoir une partie subjective ou un style de programme qui inclut une orientation personnelle. Pour les mots et expressions spécifiques à la programmation des fonctions, veuillez vous reporter aux brèves explications comprises dans la plage comprise à la fin. (* Mots avec des nombres)
Java 8 ajoute les nouvelles fonctionnalités suivantes pour la programmation de fonctions:
Avant d'entrer dans ces introductions, je voudrais essayer d'expliquer brièvement ce qu'est la programmation fonctionnelle en premier lieu.
Au sens strict, la programmation fonctionnelle est «une méthode de construction d'un programme avec des fonctions qui ont une transparence de référence (* 9) et aucun effet secondaire (* 8)», et cette définition est basée sur un langage fonctionnel. Cependant, il est maintenant possible de l'implémenter dans le style de programmation fonctionnelle même dans les langages existants, et ici nous avons décidé d'avoir une vision large de la programmation fonctionnelle et avons répertorié trois fonctionnalités.
Je pense que créer un programme avec la méthode et le but mentionnés ci-dessus peut être reconnu comme une programmation fonctionnelle dans une large perspective. De plus, la programmation fonctionnelle n'est pas liée aux méthodes de développement telles que l'analyse des exigences et les processus de conception comme orienté objet, mais est destinée au processus de mise en œuvre du programme lui-même. Afin d'effectuer la programmation fonctionnelle, il y a ceux qui prennent en charge au niveau du langage comme Haskell et Scala, et ceux qui ajoutent une API pour la programmation fonctionnelle à un langage existant tel que Java 8. On dit que Java 8 peut couvrir la plage de 1 à 2, et Haskell et Scala peuvent couvrir la plage de 1 à 3. Un langage de programmation qui peut presque éviter les effets secondaires est également appelé un langage de programmation purement fonctionnel, et de ce point de vue, Scala's 3. est considéré comme un quasi-trois plutôt qu'un pur 3. Cependant, il va sans dire que cela dépend du projet s'il est nécessaire de configurer le système avec des «fonctions qui évitent presque les effets secondaires». La programmation fonctionnelle utilise une méthode pour créer une fonction relativement petite et l'appliquer ou la combiner pour développer un système basé sur le format de programmation déclarative (* 3). Par conséquent, pour mettre en œuvre le niveau 3, il est nécessaire de bien comprendre le concept de langage fonctionnel et de programmation fonctionnelle plutôt que la méthode de programmation orientée objet conventionnelle. En outre, il est nécessaire de bien comprendre à l'avance dans quelle mesure le problème cible correspond à la programmation fonctionnelle, telle que le système lié, le middleware de la plate-forme, le cadre de la plate-forme, les actifs accumulés associés et l'environnement de développement / gestion / opération. il y a. Les éléments suivants sont généralement répertoriés comme les avantages de la programmation fonctionnelle.
Il semble y avoir des situations au cas par cas pour les 4e et 5e items, mais il semble certain que la quantité de programmation sera réduite pour les parties applicables. D'autre part, l'inconvénient est que si le système de développement peut être exprimé mathématiquement, il est théoriquement possible de le développer avec une programmation de fonction pure, mais en réalité, il existe peu d'environnements de ce type, en particulier le traitement CRUD dans les systèmes d'entreprise. On dit qu'il n'y a pas beaucoup de mérite dans l'application principale. Java8 introduit de nouveaux mécanismes tels que les interfaces fonctionnelles, les expressions lambda, les flux et facultatif pour prendre en charge la programmation fonctionnelle. Cela permet d'écrire une partie de la programmation pédagogique traditionnelle dans un style de programmation fonctionnelle (programmation déclarative). Et lors de la programmation fonctionnelle avec ce Java 8 ou version ultérieure,
Je pense qu'il y a deux cas, mais personnellement, je pense qu'il vaut mieux faire des pas (1) → (2) pour apprendre. Une chose à garder à l'esprit est que la programmation fonctionnelle ne fonctionne que sur Java 8 et supérieur. Afin de pouvoir fonctionner avec des versions plus anciennes de Java telles que Java6 et Java7, il est nécessaire de développer avec la programmation pédagogique comme auparavant, pas avec la programmation fonctionnelle.
Les principales méthodes nouvelles et mises à jour liées à la programmation fonctionnelle dans Java 8 sont les suivantes. Ces méthodes sont utilisées pour tirer parti des fonctionnalités de base de la programmation fonctionnelle. Je pense que cela peut être exprimé comme l'incorporation de la programmation fonctionnelle dans un langage orienté objet. Vous pouvez facilement trouver les détails de chacune de ces méthodes en ligne ou dans des livres. Ici, nous donnerons un aperçu de chaque méthode et un échantillon de méthodes typiques.
・ Interface fonctionnelle Les expressions Lambda et les références de méthode (* 7) peuvent être utilisées à l'aide de l'interface fonctionnelle. Vous pouvez créer les vôtres, mais plusieurs interfaces fonctionnelles standard sont disponibles.
(): Nom de la méthode principale, type d'argument → type de retour Ce qui suit est une définition simple et un exemple d'utilisation d'une interface de type de fonction personnalisée.
[Description de code associé à l'exemple d'interface] -Un programme qui spécifie un nom de passe-temps et affiche "mon passe-temps: nom de passe-temps". -L'interface fonctionnelle IHobby avec la méthode abstraite getHobby (valeur de retour: chaîne de caractères) est définie de 009 à 012. -En 003 à 005, l'implémentation du traitement de IHobby est définie à l'aide de l'expression lambda. -La méthode getHobby de IHobby est exécutée en 006.
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 }
Vous trouverez ci-dessous un exemple simple d'utilisation de l'interface fonctionnelle standard Function.
[Description du code lié à LambdaParameter] -Un programme qui multiplie la valeur spécifiée par 5 et la produit. -La méthode getFiveTimes (valeur de retour: type entier) qui multiplie la valeur par 5 est définie entre 016 et 018. -La méthode d'exécution est exécutée de 007 à 009 pour obtenir la valeur 5 fois. -L'expression lambda du deuxième argument défini en 012 de 007 à 009 est reçue par l'interface fonctionnelle. -La méthode apply de l'interface fonctionnelle est exécutée en 013.
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("résultat:" + res);
011 }
/**
*Interface de la fonction d'argument(Style Lambda)Méthode à exécuter
*/
012 public static <R> R execute(Integer value, Function<Integer, R> fnc) {
013 R rtnval = fnc.apply(value);
014 return rtnval;
015 }
/**
*Méthode pour exécuter le traitement du béton(Multipliez la valeur par 5)
*/
016 public static Integer getFiveTimes(Integer value) {
017 return value * 5;
018 }
019 }
・ Carte De nouvelles méthodes ont également été ajoutées à la classe Map existante. Les principales méthodes ajoutées sont forEach, replaceAll, computeIfAbsent, computeIfPresent, compute et merge.
Voici un exemple simple. (k: clé de mappage v: valeur de mappage p: clé de valeur d'argument: clé spécifiée)
[Description du code associé à la carte] Le type de carte est String, String. ・ ForEach (001): Sort tous les éléments de la carte au format [Clé: Valeur]. ・ ReplaceAll (002 ~): Remplacez les valeurs de tous les éléments de la carte par null → [clé] et non nul → [clé + 2 premiers caractères de valeur]. ・ ComputeIfAbsent (008 ~): a. Si la clé existe dans la clé de mappage La valeur n'est pas mise à jour et la valeur est la valeur de retour. b. Si la clé existe et que la valeur est nulle La valeur est mise à jour en [clé + "-addition"] et cette valeur est la valeur de retour. c. S'il n'existe pas dans la clé Ajoutez une valeur avec la clé et la valeur [clé + "-addition"] au mappage, et cette valeur sera la valeur de retour. ・ ComputeIfPresent (011 ~): a. Si la clé existe dans la clé de mappage La valeur est mise à jour en [Clé + Valeur + "-addition"] et cette valeur est la valeur de retour. b. Si la clé existe et que la valeur est nulle La valeur n'est pas mise à jour et null est la valeur de retour. c. S'il n'existe pas dans la clé La valeur n'est ni ajoutée ni mise à jour et null est la valeur de retour. ・ Calculer (014 ~): a. Si la clé existe dans la clé de mappage La valeur est mise à jour en [Clé + Valeur + "-addition"] et cette valeur est la valeur de retour. b. Si la clé existe et que la valeur est nulle La valeur est mise à jour en [clé + valeur (null) + "-addition"], et cette valeur est la valeur de retour. c. S'il n'existe pas dans la clé Ajoutez l'élément (clé, [clé + valeur (null) + "-addition"]) à la carte, et cette valeur sera la valeur de retour. ・ Fusionner (017 ~): a. Si la clé existe dans la clé de mappage La valeur est mise à jour en [Value + "-add"] et cette valeur est la valeur de retour. b. Si la clé existe et que la valeur est nulle La valeur est mise à jour en ["-add"](en ignorant les valeurs nulles) et cette valeur est la valeur de retour. c. S'il n'existe pas dans la clé Ajoutez l'élément (clé, ["-add"]) (ignorez la valeur nulle) à la carte, et cette valeur sera la valeur de retour.
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);
· Liste De nouvelles méthodes ont également été ajoutées à la classe List existante. Les principales méthodes ajoutées sont forEach, removeIf, replaceAll, stream et parallelStream.
Voici un exemple simple. (v: valeur de la liste valeur: valeur externe)
[Description du code associé à la liste] Le type de liste est String. ・ ForEach (001): Affiche les valeurs de tous les éléments de la liste. ・ RemoveIf (002 ~): Il y a une valeur spécifiée dans la liste: L'élément correspondant est supprimé et true est renvoyé. b. La valeur spécifiée est null: l'élément correspondant n'est pas supprimé et false est renvoyé. c. Aucune valeur spécifiée: l'élément n'est pas supprimé et false est renvoyé. ・ ReplaceAll (008 ~): Valeur non nulle pour tous les éléments: mise à jour avec les 2 premiers caractères de la valeur. b. Valeur nulle pour tous les éléments: la valeur n'est pas mise à jour. ・ Trier (014): Un tri par ordre naturel / valeur maximale nulle est effectué pour tous les éléments. ・ Flux (015): a. Obtenez le flux de la liste. ・ ParallelStream (016): a. Obtenez un flux parallèle de liste.
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();
・ API Stream Il s'agit d'une API pour la gestion des tableaux et des collections, et peut être utilisée pour le traitement de données tel que l'agrégation de valeurs. Les méthodes de flux sont classées en deux types, l'un pour le traitement intermédiaire et l'autre pour le traitement de fin, en fonction du contenu de l'opération. Exécutez la méthode de traitement de fin via 0 ou plusieurs méthodes de traitement intermédiaires. Une API Stream primitive est également disponible. Méthode de traitement intermédiaire asDoubleStream、asLongStream、boxed、distinct、filter、flatMap、flatMapToDouble、flatMapToInt、flatMapToLong、limit、map、mapToDouble、mapToInt、mapToLong、mapToObj、onClose、parallel、peek、sequential、skip、sorted、unordered Ce qui suit est une brève description des méthodes typiques.
Voici un exemple simple. (flux: instance de flux v: liste de valeurs de flux: liste externe numlimit: valeur externe)
[Description du code lié au flux (traitement intermédiaire)]
Le type de flux est Integer.
・ Filtre (001 ~):
a. Stream Extrait des multiples de 3 pour tous les éléments et renvoie avec 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);
Méthode de résiliation allMatch、anyMatch、average、collect、count、findAny、findFirst、forEach、forEachOrdered、iterator、max、min、noneMatch、reduce、spliterator、sum、summaryStatistics、toArray Voici une brève description des méthodes typiques.
Voici un exemple simple. (flux: instance de flux v: tableau de valeurs de flux: tableau externe ac: accumulateur)
[Description du code lié au flux (traitement de fin)]
・ AllMatch (001 ~):
Le flux est vérifié sous la condition de correspondance totale (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:(Plusieurs types existent)
010 //Exemple 1:Arrays.stream(array).collect(Collectors.toList());
011 //Exemple 2:list.stream().collect(StringBuilder::new, (b, v) -> b.append(v), (b1, b2) -> b1.append(b2));
//1er argument:Génération d'objet de stockage de résultat, 2ème argument:Stocker la valeur du flux 3ème argument:Jointure d'objet
count:
012 list.stream().count();
reduce:(Plusieurs types existent)
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);
· Optionnel Facultatif est une classe qui encapsule une valeur. Vous pouvez vérifier les valeurs nulles et les valeurs. Facultatif.ofNullable, Facultatif.empty (), opt.isPresent (), ...
Il existe de nombreux échantillons de plusieurs lignes sur le net et les livres, mais ici je vais vous présenter un exemple de niveau avec une certaine fonction. Cependant, la programmation de fonctions n'est pas quelque chose qui devrait être fait comme ça, mais est créée dans la perspective du codage de référence pour une compréhension rudimentaire. Les fonctions sont la gestion des stocks de produits et se composent de deux classes, la classe principale et la classe FunctionStock. Veuillez noter que la classe FunctionStock présente formellement autant d'exemples d'utilisation d'API que possible, de sorte que la programmation fonctionnelle est effectuée même là où elle n'est pas nécessaire. Aperçu de la classe StockMain: La classe principale de la gestion des stocks. Nous ne faisons pas de programmation fonctionnelle. FunctionStock: une classe qui traite réellement l'inventaire. Je fais de la programmation fonctionnelle avec plusieurs méthodes. IStock: interface de classe de traitement d'inventaire. IStockExecuter: interface de fonction Homebrew pour le traitement des stocks. Veuillez vous référer au commentaire de la classe principale pour la fonction détaillée et le commentaire du plan de méthode. Le type de programmation fonctionnelle utilisé par la marque ☆ est décrit.
[Description du code associé à StockMain] Les cartes qui stockent le nombre de stocks et les configurations d'accessoires sont définies de 013 à 014. De 025 à 036, 6 articles et la quantité de stock initiale sont définis. cd et magazine ont des accessoires. Le traitement spécifique est défini entre 016 et 022. Le livre définit deux processus d'achat et un processus de vente. magazine définit un processus de vente. Enfin, le processus de sortie de la liste d'inventaire est défini. 037 à 046 exécutent le processus d'achat avec la méthode du stock. 047 à 056 exécutent le traitement des ventes avec la méthode de vente. La quantité est négative. 057 à 066 sortent la quantité en stock du produit spécifié par la méthode get. 067 à 076 sortent la liste d'inventaire des produits avec la méthode getList. Le traitement des achats, le traitement des ventes, la sortie de la quantité d'inventaire et la sortie de la liste d'inventaire sont tous exécutés par la méthode d'exécution de FunctionStock.
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;
/**
*Classe principale de gestion des stocks
*Fonction: processus d'achat(stock), Traitement des ventes(sale), Traitement des contrôles d'inventaire(get), Traitement de la sortie de la liste d'inventaire(getList)
* (): Nom de la méthode
*Format de traitement des données de stock: nom de la méthode(Nom du produit,quantité)
*Accessoires pour chaque produit(Plusieurs possibles, mais chaque quantité est limitée à une)Est attaché, et l'inventaire de ses accessoires est également géré.
*Processus d'achat: Augmentez le nombre de produits spécifiés en stock par le nombre d'achats. Si le produit désigné n'est pas enregistré, le produit est également enregistré.
*Traitement des ventes: réduisez le nombre de produits spécifiés en stock du nombre vendu. Cependant, s'il n'y a pas de stock avec accessoires, le traitement sera arrêté.
*Traitement du contrôle des stocks: génère le nombre de produits spécifiés en stock.
*Traitement de la sortie de la liste de stock: génère le nombre de stocks de tous les produits. La liste des accessoires est également sortie.
*Traitement des erreurs: génère un message d'erreur lorsqu'il se produit et annule le traitement ultérieur.
*/
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; //Version JDK8
//private static final boolean funcOption = false; //JDK6,Version JDK7
011 public static void main(String[] args) {
012 System.out.println("**start**");
//
//Définir la valeur initiale de la carte
013 stockMap = new TreeMap<String, Integer>();
014 subStockMap = new TreeMap<String, List<String>>();
015 setInitialMap();
//
//Traitement des données d'inventaire
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 }
/**
*Méthode pour définir la valeur initiale de la carte
*/
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 }
/**
*Méthode pour effectuer le processus d'achat
*/
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 }
/**
*Méthode de traitement des ventes
*/
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 }
/**
*Méthode de sortie de la quantité en stock du produit spécifié
*/
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 }
/**
*Méthode de sortie de la liste d'inventaire
*/
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 }
/**
*Méthode pour définir la carte en objet de stock
*/
077 private static void setMap() {
078 stockObject.setStockMap(stockMap);
079 stockObject.setSubStockMap(subStockMap);
080 }
081 }
[Description du code lié au stock de fonction] Pour 028 à 042, productName, quantité et type sont définis entre 013 et 014 dans le constructeur. type représente le type de traitement et add, delname, get et getlist peuvent être spécifiés. ・ Exécuter la méthode Les données de stock spécifiées sont sorties pour confirmation à 044. Vérification des données de stock spécifiées de 045 à 048. Vérifiez les données d'inventaire avec la méthode getDataCheckFunction (). Get (), obtenez le résultat sous forme de chaîne, convertissez-le en facultatif avec Optional.ofNullable, faites un jugement null facultatif avec ifPresent et affichez une erreur avec outputErrorMessage s'il y a une erreur. Je vais. En 052, le traitement des données d'inventaire est exécuté par la méthode executeStock (). Execute () (interface de fonction auto-fabriquée IStockExecuter) et le résultat du traitement est stocké dans le type générique facultatif: Integer. En 053, le message d'erreur dans le traitement des données d'inventaire est généré par la méthode getErrorKeyFunction (). Apply (result) et sorti par outputErrorMessage. -GetDataCheckFunction, méthode 066 à 078 définit l'implémentation d'une interface fonctionnelle (type générique fournisseur: chaîne) qui vérifie les données d'inventaire (contrôle nul, etc.). ・ Méthode ExecuteStock 079 à 096 définissent une implémentation d'interface fonctionnelle (de IStockExecuter) qui traite les données d'inventaire (types de traitement: add, delname, get, getlist). Il appelle updateStock (). Get (), deleteStockName (). Get (), getStock (). Get (), outputStockList (getStockList (). Get ()), outputSubStockList (). ・ Méthode UpdateStock 097 à 126 définissent la mise en œuvre d'une interface fonctionnelle (type générique fournisseur facultatif) qui met à jour le nombre de stocks. La quantité en stock est mise à jour à l'aide de la méthode addToStockMap (). Apply (・ ・). ・ Méthode AddToStockMap Définit l'implémentation d'une interface de type de fonction (type générique BiFunction: String, Integer, Optional) qui met à jour spécifiquement le nombre de stocks de 127 à 138. La méthode de calcul de Map est utilisée pour augmenter ou diminuer le nombre de stocks. -DeleteStockName méthode 139 à 147 définissent la mise en œuvre d'une interface fonctionnelle (type générique fournisseur: facultatif) qui supprime les articles à stocker (données de stock). La méthode de suppression de Map est utilisée pour supprimer les articles en stock. ・ Méthode GetStock 148 à 154 définissent la mise en œuvre d'une interface fonctionnelle (type générique fournisseur: optionnel) qui acquiert le nombre de stocks d'un article spécifique. La quantité en stock est acquise à l'aide de la méthode getOrDefault de Map. ・ Méthode GetStockList Définit l'implémentation d'une interface fonctionnelle (type générique fournisseur: chaîne) qui récupère la liste des quantités en stock de 155 à 166. La liste d'inventaire est générée à l'aide de la méthode forEach de Map. -GetErrorKeyFunction, méthode 167 à 175 définissent l'implémentation d'une interface de type de fonction (Type générique de fonction: facultatif, chaîne) qui vérifie le résultat du traitement d'inventaire. La méthode de mappage facultative (errindex) définit la génération de message en cas d'erreur. -OutputSubStockList méthode Une liste d'accessoires est sortie de 191 à 204. Les informations de sortie d'accessoire pour un élément spécifique sont générées par la méthode de collecte après la conversion de liste en flux. -OutputErrorMessage, méthode Les messages d'erreur sont émis pour messageKey de 205 à 220. Après avoir converti messageKey en facultatif, un message d'erreur est généré par la méthode map.
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;
/**
*Classe de gestion des stocks
*/
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 "★ Le nom du produit n'est pas spécifié.",
023 "★ Le nom du produit spécifié dans la liste d'inventaire n'existe pas.",
024 "★ La quantité n'est pas spécifiée.",
025 "★ La quantité de stock sera inférieure à zéro.<%p1%> <%p2%>Pièces",
026 "★ La quantité d'accessoires en stock sera inférieure à zéro.<%p1%> <%p2%>Pièces",
027 "★ La clé est anormale.");
/**
*constructeur
*/
028 public FunctionStock(String productName, int quantity, String type) {
029 this.productName = productName;
030 this.quantity = quantity;
031 this.type = type;
032 };
/**
*constructeur
*/
033 public FunctionStock(String productName, String type) {
034 this.productName = productName;
035 this.quantity = 0;
036 this.type = type;
037 };
/**
*constructeur
*/
038 public FunctionStock(String type) {
039 this.productName = "";
040 this.quantity = 0;
041 this.type = type;
042 };
/**
*Méthode de traitement des données d'inventaire
*☆ Utilisez les méthodes facultatives des méthodes Nullable, ifPresent et orElse
*☆ Utilisez la méthode apply de l'interface Function
*/
043 public int execute() {
//Sortie des données d'inventaire
044 outputData();
//Vérification des données d'inventaire
045 Optional.ofNullable(getDataCheckFunction().get()).ifPresent(ekey -> {
046 outputErrorMessage(ekey);
047 errorKey = ekey;
048 });
049 if (null != errorKey) {
050 return -1;
051 }
//Traitement des données d'inventaire
052 Optional<Integer> result = executeStock().execute();
//Sortie d'erreur
053 outputErrorMessage(getErrorKeyFunction().apply(result));
054 return result.orElse(-1);
055 }
/**
*Méthode de sortie des données d'inventaire
*/
056 private void outputData() {
057 StringBuilder sb = new StringBuilder();
058 sb.append("Données en cours:");
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 }
/**
*Méthode de vérification des données d'inventaire
*☆ Utilise l'interface fonctionnelle Fournisseur
*/
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 }
/**
*Méthode de traitement des données d'inventaire
*☆ Utilisez l'interface de type de fonction personnalisée IStockExecuter
*☆ Utilisez la méthode vide facultative
*/
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 }
/**
*Méthode de mise à jour de la quantité de stock(Peut être augmenté ou diminué)
*☆ Utilise l'interface fonctionnelle Fournisseur
*☆ Utilisez la méthode apply de l'interface fonctionnelle BiFunction
*☆ Utilisation facultative de la méthode
*☆ Utilisez la liste pour chaque méthode
*☆ Utilisez la méthode getOrDefault de 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 }
/**
*Méthode de mise à jour de la valeur en stock du produit
*☆ Utilise l'interface fonctionnelle BiFunction
*☆ Utilisez la méthode de calcul de Map
*☆ Utilisation facultative de la méthode
*/
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 }
/**
*Méthode de suppression des données d'inventaire des marchandises
*☆ Utilise l'interface fonctionnelle Fournisseur
*☆ Utilisez facultatif deNullable, isPresent et des méthodes
*/
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 }
/**
*Méthode pour obtenir le nombre de stock
*☆ Utilise l'interface fonctionnelle Fournisseur
*☆ Utilisez la méthode getOrDefault de Map
*☆ Utilisation facultative de la méthode
*/
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 }
/**
*Méthode pour générer la liste d'inventaire
*☆ Utilise l'interface fonctionnelle Fournisseur
*☆ Utilisez la méthode Map forEach
*/
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 }
/**
*Méthode de vérification du résultat du traitement des stocks
*☆ Interface de type de fonction Utiliser la fonction
*☆ Utilisez les méthodes optionnelles map et 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 }
/**
*Méthode de sortie du nombre de stocks
*/
176 private void outputNumberStock(int result) {
177 if (-1 < result) {
178 StringBuilder sb = new StringBuilder();
179 sb.append("☆ Quantité de stock du nom de stock spécifié:");
180 sb.append(productName);
181 sb.append(" ");
182 sb.append(result);
183 sb.append("Pièces");
184 System.out.println(sb.toString());
185 }
186 }
/**
*Méthode de sortie de la liste d'inventaire
*/
187 private void outputStockList(String list) {
188 System.out.println("☆ Liste d'inventaire");
189 System.out.println(list);
190 }
/**
*Méthode de sortie de la liste d'accessoires
*☆ Utilisez les méthodes Map forEach et getOrDefault
*☆ Utilisez la méthode de flux de List
*☆ Utilisez la méthode de collecte de Stream
*/
191 private void outputSubStockList() {
192 System.out.println("☆ Liste d'accessoires");
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 }
/**
*Méthode de sortie du message d'erreur
*☆ Utilisez facultatif des méthodes Nullable et 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("★ Le traitement a été annulé.");
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 }
Ce qui suit est une brève explication des termes liés à la programmation de fonctions qui apparaissent souvent sur le net. Comme il est difficile de comprendre la monade, j'ai ajouté une explication supplémentaire.
[Explication supplémentaire de Monad] Écrivons une explication supplémentaire sur Monad du point de vue du programme. "Monad" est un terme général pour plusieurs types de monades (instances de monades), et est une classe de types en Haskell (langage fonctionnel). Les monades standard sont: Peut-être monade, Monade de liste, Monade d'identité, Soit monade, Monade d'État, Monade IO, Monade d'écrivain, Monade de lecteur, ... (En Haskell, on l'appelle aussi type Maybe, type List, ...) Pour devenir une monade, vous devez remplir les trois conditions suivantes. Si cette condition est remplie, elle peut être appelée une monade. (1) Recevez un argument de type. (2) Il peut être actionné par return et bind (>> = opérateur). return est une fonction pour mettre une valeur dans la monade. bind est un opérateur pour passer la valeur de la monade à la fonction, et il est décrit comme monade >> fonction et la valeur de retour est placée dans la monade. (3) Satisfaire aux règles établies de la Monade. Si vous remplissez les conditions, ce sera une monade, vous pouvez donc créer la vôtre en suivant les étapes ci-dessous. (1) Définissez le type pour être une monade. (2) Définissez une instance de Monad. (Inclut les implémentations de retour et de liaison.) Le but principal de cette monade est Valeur Monade >> = Fonction de type Monade 1 >> = Fonction de type Monade 2 >> = Fonction de type Monade 3 ---> Obtenir la valeur de monade Est de pouvoir exécuter des fonctions en continu comme. Dans Monad, il est également possible d'ajouter des traitements lors de la combinaison. Valeur de la monade: valeur de la monade. Fonction de type monade: fonction qui reçoit une valeur monade et renvoie le résultat du traitement sous forme de valeur monade Plus précisément, les monades peuvent être utilisées comme suit. (Ce n'est qu'un exemple. La langue est Haskell.)
*> let addOne x = Just (x + 1) --Définition de la fonction addOne (signifie simplement que c'est la valeur de Maybe monad) *> let addTwo x = Just (x + 2) --Définition de la fonction addTwo *> return 2 >> = addOne >> = addTwo --Peut-être Mettre 2 dans la monade et exécuter les fonctions addOne et addTwo
Résultat: seulement 5 Voici un exemple d'utilisation de la monade Maybe pour combiner deux fonctions, où >> = est l'opérateur de combinaison. Le retour final 2 >> = addOne >> = addTwo peut également être spécifié dans le format suivant. do return 2 addOne addTwo Je pense que les étapes suivantes sont bonnes pour mieux comprendre Monad.
Au fait, je n'ai jamais utilisé Haskell.
Définition de la monade
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
c'est tout. Merci d'avoir lu jusqu'au bout.
Recommended Posts