One year has passed since the posting, so I have not changed the essence of the content and reviewed and updated it focusing on adding explanations of the presentation source.
It has been more than 4 years since Java 8 was released in March 2014, and it has been used by many people including Java 9 and Java 10 and later. Functional programming was a hot topic when Java 8 was released. Nowadays, the term functional programming is generally recognized and pervasive among system developers. However, it seems that the actual penetration is still a long way off, as the current situation is that we do not frequently see the system development results of functional programming. And, like Java 8, existing languages are also being enhanced by incorporating a functional programming style. I can't predict what the flow will be like in the future, but I personally speculate that using functional programming styles in existing languages will become the mainstream. I don't think that a pure functional language will be a specialized usage, and Scala will not replace the Java language in Java. Functional programming seems to be in such a situation, but it is expected that it will spread in some way in the future, so I did a general survey and tried to practice simple programming in the Java 10 environment. .. In addition, I decided to post the learning results as a memorandum, thinking that it might be helpful for those who are interested. Please note that the content may have a subjective part or a program style that includes personal orientation. For words and phrases specific to functional programming, please refer to the brief explanations within the range understood at the end. (* Words with numbers)
Java 8 adds the following new features for functional programming:
Before going into these introductions, I would like to try to explain briefly what functional programming is in the first place.
In a narrow sense, functional programming is "a method of constructing a program with functions that have referential transparency (* 9) and no side effects (* 8)", and this definition is based on functional languages. However, it is now possible to implement functional programming styles even in existing languages, and here we have decided to take a broad view of functional programming and listed three features.
I think that creating a program with the above method and purpose can be recognized as functional programming from a broad perspective. In addition, functional programming is not linked to development methods such as requirements analysis design process like object-oriented programming, but is intended for the program implementation process itself. In order to perform functional programming, there are those that support at the language level such as Haskell and Scala, and those that add an API for functional programming to an existing language such as Java 8. It is said that Java 8 can cover the range from 1 to 2. Haskell and Scala can cover the range from 1 to 3. A programming language that can almost avoid side effects is also called a purely functional programming language, and from this point of view, Scala's 3. is considered to be a quasi-three rather than a pure 3. However, it goes without saying that it depends on the project whether it is necessary to configure the system with "functions that almost avoid side effects". Functional programming takes a method of creating a relatively small function and applying or combining it to develop a system, which is based on the declarative programming (* 3) format. Therefore, in order to implement level 3, it is necessary to fully understand the concept of functional languages and functional programming rather than the conventional object-oriented programming method. In addition, it is necessary to fully understand in advance how well the target problem matches functional programming, such as the system to be linked, the platform middleware, the platform framework, the related accumulated assets, and the development / management / operation environment. there is. The following items are generally cited as the advantages of functional programming.
There seems to be some case-by-case situations for the 4th and 5th items, but it seems certain that the amount of programming will be reduced for the applicable parts. On the other hand, the disadvantage is that if the development system can be expressed mathematically, it is theoretically possible to develop with pure functional programming, but in reality there are few such environments, especially CRUD processing in business systems. It is said that there is not much merit in the main application. Java8 introduces new mechanisms such as functional interfaces, lambda expressions, Streams, and Optional to support functional programming. This makes it possible to write some of the traditional imperative programming in a functional programming (declarative programming) style. And when doing functional programming in Java 8 or later,
I think there are two cases, but personally, I think it is better to take steps (1) → (2) to learn. One thing to keep in mind is that functional programming only works on Java 8 and above. In order to be able to operate with older Java versions such as Java 6 and Java 7, it is necessary to develop with imperative programming as before, not with functional programming.
The main new and updated methods related to functional programming in Java 8 are as follows. You can use these methods to take advantage of the basic functionality of functional programming. I think we can express that functional programming has been incorporated into object-oriented languages. You can easily find out more about each of these methods online or in books. Here, we will give an overview of each method and a sample of typical methods.
-Functional interface Lambda expressions and method references (* 7) can be used by using the functional interface. You can make your own, but there are several standard functional interfaces available.
(): Main method name, argument type → return type The following is a simple definition and usage sample of a self-made functional interface.
[Interface Example related code description] -A program that specifies a hobby name and outputs "my hobby: hobby name". -The functional interface IHobby with the abstract method getHobby (return value: character string) is defined in 009 to 012. -In 003 to 005, the processing implementation of IHobby is defined using a lambda expression. -The getHobby method of IHobby is executed in 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 }
Below is a simple sample using the Function standard functional interface.
[LambdaParameter related code description] -A program that multiplies the specified value by 5 and outputs it. -The method getFiveTimes (return value: Integer type) that multiplies the value by 5 is defined in 016 to 018. -The execute method is executed from 007 to 009 to get the 5 times value. -The functional interface receives the lambda expression of the second argument defined in 012 from 007 to 009. -The apply method of the functional interface is executed in 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("result:" + res);
011 }
/**
*Argument function interface(Lambda expression)Method to execute
*/
012 public static <R> R execute(Integer value, Function<Integer, R> fnc) {
013 R rtnval = fnc.apply(value);
014 return rtnval;
015 }
/**
*Method that executes specific processing(Multiply the value by 5)
*/
016 public static Integer getFiveTimes(Integer value) {
017 return value * 5;
018 }
019 }
・ Map New methods have also been added to the existing Map class. The main methods added are forEach, replaceAll, computeIfAbsent, computeIfPresent, compute and merge.
Below is a simple sample. (k: Map key v: Map value p: Argument value key: Specified key)
[Map related code description] The type of map is String, String. ・ ForEach (001): Outputs all elements of the map in the [Key: Value] format. ・ ReplaceAll (002 ~): Replace the values of all map elements with null → [key] and non-null → [key + first 2 characters of value]. ・ ComputeIfAbsent (008 ~): a. If the key exists in the map key The value is not updated and the value is the return value. b. If the key exists and the value is null The value is updated to [key + "-addition"] and that value is the return value. c. If it does not exist in the key Add a value with key and value [key + "-addition"] to map, and that value will be the return value. ・ ComputeIfPresent (011 ~): a. If the key exists in the map key The value is updated to [key + value + "-addition"] and that value is the return value. b. If the key exists and the value is null The value is not updated and the return value is null. c. If it does not exist in the key The value is not added or updated, and null is the return value. ・ Compute (014 ~): a. If the key exists in the map key The value is updated to [key + value + "-addition"] and that value is the return value. b. If the key exists and the value is null The value is updated to [key + value (null) + "-addition"], and that value is the return value. c. If it does not exist in the key Add an element (key, [key + value (null) + "-addition"]) to the map and that value will be the return value. ・ Merge (017 ~): a. If the key exists in the map key The value is updated to [value + "-add"] and that value is the return value. b. If the key exists and the value is null The value is updated to ["-add"](ignoring null values) and that value is the return value. c. If it does not exist in the key Add the element (key, ["-add"]) (ignore the null value) to the map, and that value will be the return value.
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);
・ List New methods have also been added to the existing List class. The main methods added are forEach, removeIf, replaceAll, stream, parallelStream.
Below is a simple sample. (v: list value value: external value)
[List related code description] The type of list is String. ・ ForEach (001): Outputs values for all elements of list. ・ RemoveIf (002 ~): There is a specified value in list: The corresponding element is deleted and true is returned. b. Specified value is null: The corresponding element is not deleted and false is returned. c. No specified value: The element is not deleted and false is returned. ・ ReplaceAll (008 ~): Non-null value for all elements: Updated to the first two characters of the value. b. Null value for all elements: The value is not updated. ・ Sort (014): a. Sorts all elements in natural order and null maximum value. ・ Stream (015): a. Get the Stream of list. ・ ParallelStream (016): a. Get a parallel Stream of list.
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 It is an API for handling arrays and collections, and can be used for data processing such as aggregation of values. Stream methods are classified into two types, one for intermediate processing and the other for termination processing, depending on the operation content. Executes the termination processing method via 0 or more intermediate processing methods. A primitive Stream API is also provided. Method for intermediate processing asDoubleStream、asLongStream、boxed、distinct、filter、flatMap、flatMapToDouble、flatMapToInt、flatMapToLong、limit、map、mapToDouble、mapToInt、mapToLong、mapToObj、onClose、parallel、peek、sequential、skip、sorted、unordered The following is a brief description of typical methods.
Below is a simple sample. (stream: Stream instance v: stream value list: external List numlimit: external value)
[Stream related code (intermediate processing) description]
The type of stream is Integer.
・ Filter (001 ~):
a. Stream Extracts multiples of 3 for all elements and returns with 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);
Termination method allMatch、anyMatch、average、collect、count、findAny、findFirst、forEach、forEachOrdered、iterator、max、min、noneMatch、reduce、spliterator、sum、summaryStatistics、toArray Below is a brief description of typical methods.
Below is a simple sample. (stream: Stream instance v: stream value array: external array ac: accumulator)
[Stream related code (termination processing) description]
・ AllMatch (001 ~):
The stream is checked under the all match condition (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:(Multiple types exist)
010 //Example 1:Arrays.stream(array).collect(Collectors.toList());
011 //Example 2:list.stream().collect(StringBuilder::new, (b, v) -> b.append(v), (b1, b2) -> b1.append(b2));
//1st argument:Result storage object generation, 2nd argument:Store stream value 3rd argument:Object join
count:
012 list.stream().count();
reduce:(Multiple types exist)
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 is a class that wraps one value. You can check for nulls and values. Optional.ofNullable, Optional.empty (), opt.isPresent (), ...
There are many samples of several lines on the net and books, but here I will present an example of a level with a certain function. However, functional programming is not something that should be done like this, but is created from the perspective of reference coding for a rudimentary understanding. The function is inventory management of products and consists of two classes, the main class and the FunctionStock class. Please note that the FunctionStock class formally presents as many API usage examples as possible, so functional programming is performed even where it is not needed. Class overview StockMain: The main class of inventory management. No functional programming is done. FunctionStock: A class that actually processes inventory. Functional programming is done with multiple methods. IStock: Inventory processing class interface. IStockExecuter: Homebrew function interface for inventory processing. Please refer to the comment of the main class for the detailed function and the comment of the method outline. The ☆ mark describes the type of functional programming used.
[StockMain related code description] Maps that store the number of stocks and accessory configurations are defined in 013 to 014. 6 items and initial stock quantity are set from 025 to 036. There are accessories for cd and magazine. Specific processing is set in 016 to 022. The book defines two purchasing processes and one selling process. magazine defines one sales process. Finally, the inventory list output process is defined. 037 to 046 are executing the purchase process by the stock method. 047 to 056 are executing sales processing with the sale method. The quantity is negative. 057 to 066 output the stock quantity of the specified product by the get method. 067 to 076 output the inventory list of products with the getList method. Purchasing process, sales process, inventory quantity output, and inventory list output are all executed by the execute method of 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;
/**
*Inventory management main class
*Function: Purchasing process(stock), Sales processing(sale), Inventory check processing(get), Inventory list output processing(getList)
* (): Method name
*Inventory data processing format: Method name(Product name,quantity)
*Accessories for each product(Multiple possible, but each quantity is limited to one)Is attached, and inventory management of its accessories is also performed.
*Purchasing process: Increase the number of specified products in stock by the number of purchases. If the designated product is not registered, the product is also registered.
*Sales processing: Reduce the number of specified products in stock by the number sold. However, if there is no stock including accessories, processing will be stopped.
*Inventory check processing: Outputs the inventory quantity of the specified product.
*Inventory list output processing: Outputs the number of stocks of all products. The accessory list is also output.
*Handling of errors: When an error occurs, an error message is output and the subsequent processing is stopped.
*/
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**");
//
//Set initial map value
013 stockMap = new TreeMap<String, Integer>();
014 subStockMap = new TreeMap<String, List<String>>();
015 setInitialMap();
//
//Inventory data processing
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 }
/**
*Method to set initial map value
*/
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 }
/**
*Method to perform purchasing process
*/
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 }
/**
*Method to process sales
*/
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 }
/**
*Method to output the stock quantity of the specified product
*/
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 }
/**
*Method to output inventory list
*/
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 }
/**
*Method to set map to stock object
*/
077 private static void setMap() {
078 stockObject.setStockMap(stockMap);
079 stockObject.setSubStockMap(subStockMap);
080 }
081 }
[Function Stock related code description] In 028 to 042, productName, quantity, and type are set in 013 to 014 in the constructor. type represents the type of processing, and add, delname, get, and getlist can be specified. ・ Execute method The specified inventory data is output for confirmation at 044. The specified inventory data is checked from 045 to 048. Check the inventory data with getDataCheckFunction (). Get () method, get the result String, convert it to Optional with Optional.ofNullable, make an optional null judgment with ifPresent, and display an error with outputErrorMessage if there is an error. I will. In 052, inventory data processing is executed by executeStock (). execute () method (IStockExecuter self-made function interface), and the processing result is stored in Optional generic type: Integer. In 053, error message generation in inventory data processing is performed by getErrorKeyFunction (). Apply (result) method, and outputErrorMessage is output. -GetDataCheckFunction method 066 to 078 defines the implementation of a functional interface (Supplier generic type: String) that checks inventory data (null check, etc.). ・ ExecuteStock method 079 to 096 define a functional interface (of IStockExecuter) implementation that processes inventory data (processing types: add, delname, get, getlist). It calls updateStock (). Get (), deleteStockName (). Get (), getStock (). Get (), outputStockList (getStockList (). Get ()), outputSubStockList (). ・ UpdateStock method 097 to 126 define the implementation of a functional interface (Supplier generic type Optional) that updates the inventory quantity. The inventory quantity is updated using the addToStockMap (). Apply (・ ・) method. -AddToStockMap method Defines the implementation of a functional interface (BiFunction generic type: String, Integer, Optional) that specifically updates the stock quantity in 127 to 138. The compute method of Map is used to increase or decrease the number of stocks. -DeleteStockName method In 139 to 147, the implementation of the functional interface (Supplier generic type: Optional) that deletes the inventory target item (inventory data) is defined. The remove method of Map is used to delete the item in stock. ・ GetStock method 148 to 154 define the implementation of a functional interface (Supplier generic type: Optional) that acquires the inventory quantity of a specific item. The stock quantity is acquired using the getOrDefault method of Map. -GetStockList method Defines the implementation of a functional interface (Supplier generic type: String) that retrieves the stock quantity list in 155 to 166. The inventory list is generated using Map's forEach method. -GetErrorKeyFunction method 167 to 175 define the implementation of a functional interface (Function generic type: Optional, String) that checks the inventory processing result. Optional (errindex) map method defines message generation in case of error. -OutputSubStockList method A list of accessories is output from 191 to 204. The accessory output information for a specific item is generated by the collect method after converting from list to stream. -OutputErrorMessage method Error message is output for messageKey from 205 to 220. After converting messageKey to Optional, an error message is generated by the map method.
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;
/**
*Inventory management class
*/
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 "★ The product name is not specified.",
023 "★ The product name specified in the inventory list does not exist.",
024 "★ The quantity is not specified.",
025 "★ Inventory will be less than zero.<%p1%> <%p2%>Pieces",
026 "★ The inventory of accessories will be less than zero.<%p1%> <%p2%>Pieces",
027 "★ The key is abnormal.");
/**
*constructor
*/
028 public FunctionStock(String productName, int quantity, String type) {
029 this.productName = productName;
030 this.quantity = quantity;
031 this.type = type;
032 };
/**
*constructor
*/
033 public FunctionStock(String productName, String type) {
034 this.productName = productName;
035 this.quantity = 0;
036 this.type = type;
037 };
/**
*constructor
*/
038 public FunctionStock(String type) {
039 this.productName = "";
040 this.quantity = 0;
041 this.type = type;
042 };
/**
*Methods for processing inventory data
*☆ Use Optional ofNullable, ifPresent and orElse methods
*☆ Use the apply method of the Function interface
*/
043 public int execute() {
//Inventory data output
044 outputData();
//Inventory data check
045 Optional.ofNullable(getDataCheckFunction().get()).ifPresent(ekey -> {
046 outputErrorMessage(ekey);
047 errorKey = ekey;
048 });
049 if (null != errorKey) {
050 return -1;
051 }
//Inventory data processing
052 Optional<Integer> result = executeStock().execute();
//Error output
053 outputErrorMessage(getErrorKeyFunction().apply(result));
054 return result.orElse(-1);
055 }
/**
*Method to output inventory data
*/
056 private void outputData() {
057 StringBuilder sb = new StringBuilder();
058 sb.append("Processing data:");
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 }
/**
*Method to check inventory data
*☆ Uses functional interface Supplier
*/
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 }
/**
*Methods for processing inventory data
*☆ Use self-made functional interface IStockExecuter
*☆ Use Optional empty method
*/
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 }
/**
*Method to update inventory quantity(Can be increased or decreased)
*☆ Uses functional interface Supplier
*☆ Use the apply method of the functional interface BiFunction
*☆ Use Optional of method
*☆ Use List forEach method
*☆ Use getOrDefault method of 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 }
/**
*Method to update inventory value of goods
*☆ Uses functional interface BiFunction
*☆ Use Map's compute method
*☆ Use Optional of method
*/
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 }
/**
*Method to delete inventory data of goods
*☆ Uses functional interface Supplier
*☆ Use Optional ofNullable, isPresent and of methods
*/
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 }
/**
*Method to get the stock quantity
*☆ Uses functional interface Supplier
*☆ Use getOrDefault method of Map
*☆ Use Optional of method
*/
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 }
/**
*Method to generate inventory list
*☆ Uses functional interface Supplier
*☆ Use Map forEach method
*/
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 }
/**
*Method to check inventory processing result
*☆ Uses functional interface Function
*☆ Use Optional map and orElse methods
*/
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 }
/**
*Method to output the number of stocks
*/
176 private void outputNumberStock(int result) {
177 if (-1 < result) {
178 StringBuilder sb = new StringBuilder();
179 sb.append("☆ Inventory quantity of the specified inventory name:");
180 sb.append(productName);
181 sb.append(" ");
182 sb.append(result);
183 sb.append("Pieces");
184 System.out.println(sb.toString());
185 }
186 }
/**
*Method to output inventory list
*/
187 private void outputStockList(String list) {
188 System.out.println("☆ Inventory list");
189 System.out.println(list);
190 }
/**
*Method to output accessory list
*☆ Use Map forEach and getOrDefault methods
*☆ Use List's stream method
*☆ Use Stream's collect method
*/
191 private void outputSubStockList() {
192 System.out.println("☆ Accessory list");
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 }
/**
*Method to output error message
*☆ Use Optional ofNullable and map methods
*/
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("★ Processing has been cancelled.");
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 }
Below is a brief explanation of the terms related to functional programming that often appear on the net. Since it is difficult to understand monads, I added an additional explanation.
[Additional explanation of monads] Let's write an additional explanation about monads from a program perspective. "Monad" is a general term for several types of monads (monad instances), and is a type class in Haskell (functional language). The standard monads are: Maybe monad, List monad, Identity monad, Either monad, State monad, IO monad, Writer monad, Reader monad, ... (In Haskell, it is also called Maybe type, List type, ...) To become a monad, you need to meet the following three conditions. If this condition is met, it can be called a monad. (1) Receive one type argument. (2) It can be operated by return and bind (>> = operator). return is a function to put a value in a monad. bind is an operator for passing a monad value to a function, and it is described as monad >> function and the return value is put in the monad. (3) Satisfy the established monadic rules. If you meet the conditions, it will be a monad, so you can make your own by following the steps below. (1) Define the type to be a monad. (2) Define an instance of Monad. (Includes return and bind implementations.) The main purpose of this monad is Monad value >> = Monad type function 1 >> = Monad type function 2 >> = Monad type function 3 ---> Get monad value Is to be able to execute functions continuously like. It is also possible to add some processing when combining in monads. Monad value: The value that a monad has. Monad type function: A function that receives a monad value and returns the processing result as a monad value. Specifically, monads can be used as follows. (It's just an example. The language is Haskell.)
*> let addOne x = Just (x + 1) --Definition of function addOne (Just means that it is the value of the Maybe monad) *> let addTwo x = Just (x + 2) --Definition of function addTwo *> return 2 >> = addOne >> = addTwo --Maybe Put 2 in the monad and execute the functions addOne and addTwo
Result: Just 5 This is an example of using the Maybe monad to combine two functions, where >> = is the operator for combining. The final return 2 >> = addOne >> = addTwo can also be specified in the following format. do return 2 addOne addTwo I think the following steps are good for understanding monads further.
By the way, I have never used Haskell.
Monad definition
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
that's all. Thank you for reading to the end.
Recommended Posts