2017年10月18日 星期三

[ Java 文章收集 ] An Introduction to Functional Programming in Java 8: Part 1 - Functions as Objects

Source From Here 
Preface 
After you’ve read in Part 0 why functional programming is cool, we will make our first big steps into this topic today. In Java 8, functions became first class. Therefore, you can take functions as arguments of other functions, return functions and store functions as objects

Why should you store a function as an object? 

1. Make “super private” functions 
As you know, code quality is important. That’s the reason we use private functions to reduce the methods one object of a class has. We don’t want to show the underlying code to others, they just have to work with some public methods on the object. But what if we want to create functions in our class which are visible to just one method and invisble to the rest of the class? With functions as first class objects, We can store the function in a single object, which can be seen just in this very one method. 

2. Upgrade Design Patterns 
If you ever worked with on a big software project you know how messy it can become. That’s the reason design patterns were invented. One of the cooler ones is the Strategy Pattern. I will write a detailed post about it later on, but what it basically does is to switch similar algorithms, depending on a parameter. For each algorithm, you have to write your own class, which implements a function from an interface. But when you can store functions in an object, you just need one “function object” for each algorithm. That makes the code much clearer and smaller. 

3. Create “higher-order” functions 
Now comes the fun part. You can use every object as a parameter of a method. So why not call a method with a function argument? Methods which take a function as a parameter or return one, are called higher-order functions. Before I can give you an example we have to learn how to store a function in an object. 

Storing a function in an Object 
In Java 8, the java.util.Function Interface was introduced. It can store a function which takes one argument and returns an object. The Generic T is the type of the argument and R the type of the object you return. 

Example: compute function 
This is a very easy example of a higher-order function. It takes a function and an Integer and computes the given function with the Integer. 
  1. public static Integer compute(Function function, Integer value) {  
  2.     return function.apply(value);  
  3. }  
And now, we want to use this function to invert an Integer 
  1. package fp.others;  
  2.   
  3. import java.util.function.Function;  
  4.   
  5. public class AwesomeClass {  
  6.     public static Integer compute(Function function, Integer value) {  
  7.         return function.apply(value);  
  8.     }  
  9.       
  10.     private static Integer invert(Integer value) {  
  11.         return -value;  
  12.     }  
  13.   
  14.     public static Integer invertTheNumber(){  
  15.         Integer toInvert = 5;  
  16.         Function invertFunction = AwesomeClass::invert;  
  17.         return compute(invertFunction, toInvert);  
  18.     }  
  19. }  
There are two interesting lines here. The first one is: 
  1. return function.apply(value);  
The apply method of a Function object just takes an arguments and returns the method’s output. In our example, you could also write: 
  1. return invert(value);  
The second interesting line is this one: 
  1. Function invertFunction = AwesomeClass::invert;  
What we use here is a so called method reference. We make the function invert() to a Function object by using the :: operator. It is one of two ways to store a function in an object. But this code doesn’t make anything easier. You could refactor it like this: 
  1. public class AwesomeClass {  
  2.   
  3.     private static Integer invert(Integer value) {  
  4.         return -value;  
  5.     }  
  6.   
  7.     public static Integer invertTheNumber(){  
  8.         Integer toInvert = 5;  
  9.         return invert(toInvert);  
  10.     }  
  11.       
  12. }  
It doesn’t need an compute function or any fP at all, but it still looks nicer. To make our fP code useful, we have to introduce our second way to store a function in an object. And this is by using anonymous functions, or so called Lambdas

How to work with Lambdas 
To work with Lambdas in Java 8, we have to look at a new syntax to handle them properly. 

Example: Adding Two Integers 
In good old Java 7, you can write a method to add two Integers like this: 
  1. public Integer add(Integer a, Integer b) {  
  2.     return a + b;  
  3. }  
And this is a Java 8 Lambda which does exactly the same: 
  1. BiFunction add = (a, b) -> a + b;  
That’s pretty straightforward, isn’t it? BiFunction is another Interface in java.util to represent a function with two arguments and one return object. In the brackets of the Lambda, you define the arguments. You don’t have to give them a type, you just have to say how many there are and how each should be called. This is equivalent to 
  1. (Integer a, Integer b)  
in the Java 7 method. Next off, you have the “->” arrow. It is equivalent to the curly brackets and separate the function’s head from its body And after the arrow, you can work with the arguments. If you have just one calculation to make, return isn’t necessary because it returns the result of this line. You can also make the function’s body bigger by using curly brackets. 
  1. BiFunction add = (a,b) -> {  
  2.     Integer result = a + b;  
  3.     return result;  
  4. };  
But most of the times, you just need one line and therefore no brackets and no return keyword. Making the compute Function Nicer. With that in mind, we can refactor our previous use of the compute function. 
  1. public class AwesomeClass {  
  2.     public static Integer invertTheNumber(){  
  3.         Integer toInvert = 5;  
  4.         return compute((a) -> -a, toInvert);  
  5.     }  
  6. }  
Now that’s some beautiful code! We can make our invert function to a Lambda. This makes the code nicer than our old fP version and the Java 7 example. We don’t have to create an extra method to invert the Integer, we just have to use a small lambda which does the work. You might ask yourself now why we don’t just return -value. And in this case, it would be better. However, if we want to change the function at runtime, our version can be used for this. 
  1. public class AwesomeClass {  
  2.     public static Integer changeTheNumber(Function func){  
  3.         Integer toChange = 5;  
  4.         return compute(func, toChange);  
  5.     }  
  6. }  
Conclusion 
That’s it for today! We have made our first big steps towards functional programming in Java 8. First off, we have seen a lot of benefits of fP. After that, we have used our first function as an argument in another method by using method references and Lambdas (anonymous functions). In part 2, we will introduce Optionals and how we can work with them properly. 

Supplement 
An Introduction to Functional Programming in Java 8: Part 2 - Optionals 
An Introduction to Functional Programming in Java 8: Part 3 - Streams

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...