Three ways to achieve functional programming

Three ways to achieve functional programming

Summary

\quad After the introduction of functional programming Java8, many complex code can be greatly simplified, even a word can be simplified. Here mainly through an example, using a Lambda expression analysis using the static method, and a simplified example of a method of the advantages and disadvantages of the code.

table of Contents

(Click to jump directly)
* 1. Introduction
* 2. Use Lambda Expressions
* 3. Use the static method
* 4. The method of Example
* 5. Summary

1 Introduction

\quadThrough this example, one can realize how poor their own previously written code readability, on the other hand can know how to use elegant interface. Interfaces previously used when only know that implements this interface, on behalf of the class has some ability. But by following this example, I saw the interface can also be used in the method. When implementation of the interface, but only requires providing (input / Return Value) type from the lambda expression.

2. Use Lambda Expressions

Look at the following code:
The map of k, v values are printed with a different connector
public static void printWithComma(Map<String, String> map1, Map<String, String> map2) {
        for (Map.Entry<String, String> entry : map1.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "," + value);
        }

        for (Map.Entry<String, String> entry : map2.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "," + value);
        }
    }

    public static void printWithDash(Map<String, String> map1, Map<String, String> map2) {
        for (Map.Entry<String, String> entry : map1.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "-" + value);
        }

        for (Map.Entry<String, String> entry : map2.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "-" + value);
        }
    }

    public static void printWithColon(Map<String, String> map1, Map<String, String> map2) {
        for (Map.Entry<String, String> entry : map1.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + ":" + value);
        }

        for (Map.Entry<String, String> entry : map2.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + ":" + value);
        }
    }
    
复制代码

After reading found inside a lot of duplicate code, naturally think, one of the common code can be extracted. And the function is a two input map, to give a void, in line BiConsumer interface setting. Therefore, the common interface may be implemented BiConsumer extraction method, the realization of code reuse.
code show as below:

public static void printWithConsumer(
         Map<String, String> map1,
         Map<String, String> map2,
         BiConsumer<String, String> consumer) {
     map1.forEach(consumer);
     map2.forEach(consumer);
 }
复制代码

The method of printing can be reduced to the sentence:

public static void printWithComma(Map<String, String> map1, Map<String, String> map2) {
        printWithConsumer(map1, map2, (s, s2) -> System.out.println(s+","+s2));
    }
复制代码

3. Use the static method

\quad Also the use of a second example of the second method is simplified.

 public static void printWithDash(Map<String, String> map1, Map<String, String> map2) {
        printWithConsumer(map1, map2, RefactorToConsumer::staticPrintWithDash);
    }

    public static void staticPrintWithDash(String s1, String s2) {
        System.out.println(s1 + "-" + s2);
    }
复制代码

\quad定义的静态方法消耗两个String,得到一个void,符合BiCounsumer的约定,所以可以使用静态方法引用的方式简化代码。
\quad分析二者优缺点:
1.使用静态方法可以给方法取名字,这样更加直观,更容易被理解。
2.使用静态方法可以在方法中写较为复杂的代码,而Lambda中一般就是一两句话。所以需要较多的代码实现的时候,最好还是在静态方法中声明。

4.使用实例方法

\quad 为了便于理解,这里使用另外一个简单的例子: 对一个User类实现过滤
代码如下:

public class User {
   
    private final Integer id;
    private final String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    
    // 过滤姓张的用户
    public static List<User> filterZhangUsers(List<User> users) {
        List<User> list = new ArrayList<>();
        for (User user:users
             ) {
            if (user.name.startsWith("张")){
                list.add(user);
            }
        }
        return list;
    }
}
复制代码

\quad 为了减少排版,我这里只写了一个过滤器,但是可以想象如果需要过滤姓王的,ID为偶数的User...我们就可以将其抽取出来,形成一个公共的抽取方法。无论用前面的Lambda表达式也好,用静态方法也可以,实现Predicate接口即可。除此之外,我们还发现这个判定的过程其实就是User类型转换为boolean类型的过程,而恰好方法就是在User类中定义的。所以不必将方法定义成static类型,使用实例方法即可。
代码如下:

public static List<User> filterZhangUsers(List<User> users) {
       return filter(users,User::filterNameStartWithZhang);
    }
    
    public boolean filterNameStartWithZhang(){
        return this.name.startsWith("张");
    }

    public static List<User> filter(List<User> users, Predicate<User> predicate) {
        List<User> results = new ArrayList<>();
        for (User user : users
        ) {
            if (predicate.test(user)) {
                results.add(user);
            }
        }
        return results;
    }
复制代码

\quad由于 filterNameStartWithZhang()方法是非静态的,在方法形参表中看似是空的,实际上形参是(User this),符合Predicate的从某一类型到boolean的设定。

5.总结

Summary:
\quad1. a lot of duplicate code refactoring, is a very necessary thing. Not only tangible reduce the amount of code, but also in virtually reduced the chance of a bug, and greatly increases the readability of the code.
\quadNote 2. Lambda expressions, variable references in expressions need to be effectively final type, otherwise it will report
"Variable used in lambda expression should be final or effectively final".

Solution:
1. Atomic types of parameters may be used. 2. Parameters can be declared as a global type.
Details refer to this article: zhuanlan.zhihu.com/p/82921974

Guess you like

Origin juejin.im/post/5d819a03e51d4561c83e7d08