2017年11月2日 星期四

[ Java 文章收集 ] Composing functions using compose and andThen

Source From Here 
What is function composition? 
It all has to do with creating small reusable functions that you can combine to compose new functions. 

Now, how can we achieve this using compose and andThen? 
Let's first define two simple functions - times2 and squared
  1. Function times2 = e -> e * 2;  
  2. Function squared = e -> e * e;    
Next, let's combine them, using compose and andThen
  1. times2.compose(squared).apply(4);    
  2. // Returns 32 = (4^2) * 2  
  3.   
  4. times2.andThen(squared).apply(4);    
  5. // Returns 64 = (4*2)^2  
As you can see, the difference between compose and andThen is the order they execute the functions. While the compose function executes the caller last and the parameter first, the andThen executes the caller first and the parameter last. 

Let's start composing functions 
Let's create an example to see how we can use this approach to create small pieces of reusable code - then put them together in different ways. Consider the following. We have a list of articles and we need to filter the articles based on different requirements. Let's start by introducing two basic functions - byAuthor and byTag - that filter articles based on an author and a tag. 
  1. BiFunction, List
    > byAuthor =  
  2.     (name, articles) -> articles.stream()  
  3.         .filter(a -> a.getAuthor().equals(name))  
  4.         .collect(Collectors.toList());  
  5.   
  6. BiFunction, List
    > byTag =    
  7.     (tag, articles) -> articles.stream()  
  8.         .filter(a -> a.getTags().contains(tag))  
  9.         .collect(Collectors.toList());  
Both of these functions are BiFunctions - meaning they take two parameters. byAuthor takes the name of an author and the list of articles, returning a list of the articles written by the author requested; Same goes for byTag. It takes a tag and the list of articles, returning articles with the requested tag. 

Since BiFunction takes two arguments, it only offers the andThen function. You can't put the result of a function into a function that takes two arguments, hence the lack of the compose function. Moving on - let's also throw in a basic function that sorts a list of articles from newest to oldest and a function that returns the first article a list. 
  1. Function, List
    > sortByDate =    
  2.                 articles -> articles.stream()  
  3.                     .sorted((x, y) -> y.published().compareTo(x.published()))  
  4.                     .collect(Collectors.toList());  
  5.   
  6. Function, Optional
    > first =  a -> a.stream().findFirst();  
Now that we have our basic functions, let's see how we can use them to compose new functions. Let's start by composing a function that will return the article that was most recently published
  1. Function, Optional
    > newest = first.compose(sortByDate);  
Using the functions first and sortByDate that we created earlier, we're able to create a new function that will return the newest article in a given list. We can continue to mix these function in several ways to compose functions with new meanings without repeating code. Finding an author's newest masterpiece
  1. BiFunction, Optional
    > newestByAuthor =  byAuthor.andThen(newest);  
Or just order an author's articles. 
  1. BiFunction, List
    > byAuthorSorted =    
  2.     byAuthor.andThen(sortByDate);  

Or maybe you don't care about the author. You just want the newest article based on your favourite tag. 
  1. BiFunction, Optional
    > newestByTag =    
  2.     byTag.andThen(newest);  
The point I'm trying to make is that the Function interface and it's compose functions can make it easier and more intriguing to stay DRY by creating small building blocks that can be combined to fit your needs. There you go - a few simple ways to compose functions using compose and andThen. Give it a try as well!

沒有留言:

張貼留言

[ Python 常見問題 ] Get all object attributes in Python?

Source From  Here   Question   Is there a way to  get all attributes/methods/fields/etc. of an object in Python ?  vars()  is close to what ...