激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 使用java8的方法引用替換硬編碼的示例代碼

使用java8的方法引用替換硬編碼的示例代碼

2020-09-09 13:51我恰芙蓉王 Java教程

這篇文章主要介紹了使用java8的方法引用替換硬編碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

背景

想必大家在項目中都有遇到把一個列表的多個字段累加求和的情況,也就是一個列表的總計。有的童鞋問,這個不是給前端做的嗎?后端不是只需要把列表返回就行了嘛。。。沒錯,我也是這樣想的,但是在一場和前端的撕逼大戰中敗下陣來之后,這個東西就落在我身上了。當時由于工期原因,時間比較緊,也就不考慮效率和易用性了,只是滿足當時的需求,就隨便寫了個方法統計求和。目前稍微閑下來了,就把原來的代碼優化下。我們先來看一下原來的代碼...

原代碼

工具類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
 
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
/**
 * * @ClassName CalculationUtil
 * * @Description TODO(計算工具類)
 * * @Author 我恰芙蓉王
 * * @Date 2020年04月21日 11:37
 * * @Version 1.0.0
 *
 **/
public class CalculationUtil {
 
  //拼接get set方法的常量
  public static final String GET = "get";
  public static final String SET = "set";
 
  /**
   * 功能描述: 公用統計小計方法
   *
   * @param list  原數據列表集合
   * @param fields 運算的屬性數組
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統計好的對象
   **/
  public static <T> T totalCalculationForBigDecimal(List<T> list, String... fields) throws Exception {
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    Class clazz = list.get(0).getClass();
    //返回值
    Object object = clazz.newInstance();
    list.stream().forEach(v ->
        Arrays.asList(fields).parallelStream().forEach(t -> {
          try {
            String field = StringUtils.capitalize(t);
            //獲取get方法
            Method getMethod = clazz.getMethod(GET + field);
            //獲取set方法
            Method setMethod = clazz.getMethod(SET + field, BigDecimal.class);
 
            Object objectValue = getMethod.invoke(object);
            setMethod.invoke(object, (objectValue == null ? BigDecimal.ZERO : (BigDecimal) objectValue).add((BigDecimal) getMethod.invoke(v)));
          } catch (Exception e) {
            e.printStackTrace();
          }
        })
    );
    return (T) object;
  }
 
  /**
   * 功能描述: 公用統計小計方法
   *
   * @param list  原數據列表集合
   * @param fields 運算的屬性數組
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統計好的對象
   **/
  public static <T> T totalCalculationForDouble(List<T> list, String... fields) throws Exception {
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    Class clazz = list.get(0).getClass();
    //返回值
    Object object = clazz.newInstance();
    list.stream().forEach(v ->
        Arrays.asList(fields).parallelStream().forEach(t -> {
          try {
            String field = StringUtils.capitalize(t);
            //獲取get方法
            Method getMethod = clazz.getMethod(GET + field);
            //獲取set方法
            Method setMethod = clazz.getMethod(SET + field, Double.class);
 
            Object objectValue = getMethod.invoke(object);
            setMethod.invoke(object, add((objectValue == null ? new Double(0) : (Double) objectValue), (Double) getMethod.invoke(v)));
          } catch (Exception e) {
            e.printStackTrace();
          }
        })
    );
 
    return (T) object;
  }
 
  /**
   * 功能描述: 公用統計小計方法
   *
   * @param list  原數據列表集合
   * @param fields 運算的屬性數組
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統計好的對象
   **/
  public static <T> T totalCalculationForFloat(List<T> list, String... fields) throws Exception {
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    Class clazz = list.get(0).getClass();
    //返回值
    Object object = clazz.newInstance();
    list.stream().forEach(v ->
        Arrays.asList(fields).parallelStream().forEach(t -> {
          try {
            String field = StringUtils.capitalize(t);
 
            //獲取get方法
            Method getMethod = clazz.getMethod(GET + field);
            //獲取set方法
            Method setMethod = clazz.getMethod(SET + field, Float.class);
 
            Object objectValue = getMethod.invoke(object);
            setMethod.invoke(object, add((objectValue == null ? new Float(0) : (Float) objectValue), (Float) getMethod.invoke(v)));
          } catch (Exception e) {
            e.printStackTrace();
          }
        })
    );
    return (T) object;
  }
 
  /**
   * 提供精確的加法運算。
   *
   * @param v1 被加數
   * @param v2 加數
   * @return 兩個參數的和
   */
  public static Double add(Double v1, Double v2) {
    BigDecimal b1 = new BigDecimal(v1.toString());
    BigDecimal b2 = new BigDecimal(v2.toString());
    return b1.add(b2).doubleValue();
  }
 
  /**
   * 提供精確的加法運算。
   *
   * @param v1 被加數
   * @param v2 加數
   * @return 兩個參數的和
   */
  public static Float add(Float v1, Float v2) {
    BigDecimal b1 = new BigDecimal(v1.toString());
    BigDecimal b2 = new BigDecimal(v2.toString());
    return b1.add(b2).floatValue();
  }
}

實體類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
 
  //訂單號
  private String orderNo;
 
  //訂單金額
  private Double money;
 
  //折扣
  private Double discount;
 
}
 
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Phone {
 
  //手機名
  private String name;
 
  //成本
  private BigDecimal cost;
 
  //售價
  private BigDecimal price;
}

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static void main(String[] args) throws Exception {
  List<Order> orderList = new ArrayList<Order>() {
    {
      add(new Order("D20111111", 256.45, 11.11));
      add(new Order("D20111112", 123.85, 1.11));
      add(new Order("D20111113", 546.13, 2.14));
      add(new Order("D20111114", 636.44, 0.88));
    }
  };
 
  List<Phone> phoneList = new ArrayList<Phone>() {
    {
      add(new Phone("蘋果", new BigDecimal("123.11"), new BigDecimal("222.22")));
      add(new Phone("三星", new BigDecimal("123.11"), new BigDecimal("222.22")));
      add(new Phone("華為", new BigDecimal("123.11"), new BigDecimal("222.22")));
      add(new Phone("小米", new BigDecimal("123.11"), new BigDecimal("222.22")));
    }
  };
 
  Order orderTotal = totalCalculationForDouble(orderList, "money", "discount");
  System.out.println("總計數據為 :" + orderTotal);
 
  Phone phoneTotal = totalCalculationForBigDecimal(phoneList, "cost", "price");
  System.out.println("總計數據為 :" + phoneTotal);
}

使用java8的方法引用替換硬編碼的示例代碼

通過以上代碼可以看出,效果是實現了,但是缺點也是很明顯的:

1.太過冗余,相同代碼太多,多個方法只有少數代碼不相同(工具類中黃色標注的地方);

2.效率低,列表中每個元素的每個屬性都要用到反射賦值;

3.靈活性不夠,要求實體類中需要參加運算的屬性都為同一類型,即必須都為Double,或必須都為BigDecimal;

4.硬編碼,直接在方法調用時把實體類中的字段寫死,既不符合JAVA編碼規范也容易出錯,而且當該實體類中的屬性名變更的時候,IDE無法提示我們相應的傳參的變更,極容易踩坑。

因為項目中用的JDK版本是1.8,當時在寫的時候就想通過方法引用規避掉這種硬編碼的方式,因為在Mybatis-Plus中也有用到方法引用賦值條件參數的情況,但還是因為時間緊急,就沒去研究了。

今天就順著這個方向去找了一下實現的方法,把代碼優化了部分,如下:

優化后

首先,我是想通過傳參為方法引用的方式來獲取Getter方法對應的屬性名,通過了解,JDK8中已經給我們提供了實現方式,首先聲明一個自定義函數式接口(需要實現Serializable)

?
1
2
3
4
@FunctionalInterface
public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {
 
}

然后定義一個反射工具類去解析這個自定義函數式接口,在此工具類中有對方法引用解析的具體實現,在此類中規避掉缺點4

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
 
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
/**
 * @ClassName ReflectionUtil
 * @Description TODO(反射工具類)
 * @Author 我恰芙蓉王
 * @Date 2020年09月08日 15:10
 * @Version 2.0.0
 **/
 
public class ReflectionUtil {
 
  public static final String GET = "get";
  public static final String SET = "set";
 
  /**
   * 功能描述: 通過get方法的方法引用返回對應的Field
   *
   * @param function
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年09月08日 16:20:56
   * @return: java.lang.reflect.Field
   **/
  public static <T> Field getField(SerializableFunction<T, ?> function) {
    try {
      /**
       * 1.獲取SerializedLambda
       */
      Method method = function.getClass().getDeclaredMethod("writeReplace");
      method.setAccessible(Boolean.TRUE);
      /**
       * 2.利用jdk的SerializedLambda,解析方法引用,implMethodName 即為Field對應的Getter方法名
       */
      SerializedLambda serializedLambda = (SerializedLambda) method.invoke(function);
      //獲取get方法的方法名
      String getter = serializedLambda.getImplMethodName();
      //獲取屬性名
      String fieldName = StringUtils.uncapitalize(getter.replace(GET, ""));
      /**
       * 3.獲取的Class是字符串,并且包名是“/”分割,需要替換成“.”,才能獲取到對應的Class對象
       */
      String declaredClass = serializedLambda.getImplClass().replace("/", ".");
      Class clazz = Class.forName(declaredClass, false, ClassUtils.getDefaultClassLoader());
      /**
       * 4.通過Spring中的反射工具類獲取Class中定義的Field
       */
      return ReflectionUtils.findField(clazz, fieldName);
    } catch (ReflectiveOperationException e) {
      throw new RuntimeException(e);
    }
  }
}

接著改寫原來計算工具類中的代碼,在此類中將原缺點的1,2,3點都規避了,將原來冗余的多個方法精簡成一個 totalCalculation ,通過 methodMap 對象將get,set方法緩存(但此緩存還有優化的空間,可以將方法中的緩存對象提到tomcat內存或redis中),通過動態獲取字段類型來實現不同類型的累加運算

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
 
import static io.renren.modules.test1.ReflectionUtil.GET;
import static io.renren.modules.test1.ReflectionUtil.SET;
 
/**
 * * @ClassName CalculationUtil
 * * @Description TODO(計算工具類)
 * * @Author 我恰芙蓉王
 * * @Date 2020年04月21日 11:37
 * * @Version 1.0.0
 *
 **/
public class CalculationUtil {
 
  /**
   * 功能描述: 公用統計小計方法
   *
   * @param list   原數據列表集合
   * @param functions 參與運算的方法引用
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統計好的對象
   **/
  public static <T> T totalCalculation(List<T> list, SerializableFunction<T, ?>... functions) throws Exception {
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    //獲取集合中類型的class對象
    Class clazz = list.get(0).getClass();
 
    //Getter Setter緩存
    Map<SerializableFunction, Map<String, Method>> methodMap = new ConcurrentHashMap<>();
    //遍歷字段,將Getter Setter放入緩存中
    for (SerializableFunction function : functions) {
      Field field = ReflectionUtil.getField(function);
      //獲取get方法
      Method getMethod = clazz.getMethod(GET + StringUtils.capitalize(field.getName()));
      //獲取set方法
      Method setMethod = clazz.getMethod(SET + StringUtils.capitalize(field.getName()), field.getType());
      //將get set方法封裝成一個map放入緩存中
      methodMap.put(function, new HashMap<String, Method>() {
        {
          put(GET, getMethod);
          put(SET, setMethod);
        }
      });
    }
 
    //計算
    T result = list.parallelStream().reduce((x, y) -> {
      try {
        Object newObject = x.getClass().newInstance();
        Arrays.asList(functions).parallelStream().forEach(f -> {
          try {
            Map<String, Method> fieldMap = methodMap.get(f);
            //獲取緩存的get方法
            Method getMethod = fieldMap.get(GET);
            //獲取緩存的set方法
            Method setMethod = fieldMap.get(SET);
            //調用x參數t屬性的get方法
            Object xValue = getMethod.invoke(x);
            //調用y參數t屬性的get方法
            Object yValue = getMethod.invoke(y);
            //反射賦值到newObject對象
            setMethod.invoke(newObject, add(xValue, yValue, getMethod.getReturnType()));
          } catch (Exception e) {
            e.printStackTrace();
          }
        });
        return (T) newObject;
      } catch (Exception e) {
        e.printStackTrace();
      }
      return null;
    }).get();
 
    return result;
  }
 
  /**
   * 功能描述: 提供精確的加法運算
   *
   * @param v1  加數
   * @param v2  被加數
   * @param clazz 參數的class類型
   * @創建人: 我恰芙蓉王
   * @創建時間: 2020年09月08日 10:55:56
   * @return: java.lang.Object 相加之和
   **/
  public static Object add(Object v1, Object v2, Class clazz) throws Exception {
    BigDecimal b1 = new BigDecimal(v1.toString());
    BigDecimal b2 = new BigDecimal(v2.toString());
    Constructor constructor = clazz.getConstructor(String.class);
    return constructor.newInstance(b1.add(b2).toString());
  }
 
}

測試實體類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
 
  //名字
  private String name;
 
  //年齡
  private Integer age;
 
  //存款
  private BigDecimal money;
 
  //身高
  private Double height;
}

調用

?
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws Exception {
  List<People> list = new ArrayList<People>() {
    {
      add(new People("張三", 18, BigDecimal.valueOf(10000), 168.45));
      add(new People("李四", 20, BigDecimal.valueOf(20000), 155.68));
      add(new People("王五", 25, BigDecimal.valueOf(30000), 161.54));
      add(new People("趙六", 21, BigDecimal.valueOf(30000), 166.66));
    }
  };
  People total = CalculationUtil.totalCalculation(list, People::getAge, People::getMoney, People::getHeight);
  System.out.println("總計數據為 :" + total);
}

使用java8的方法引用替換硬編碼的示例代碼

總結

java8的lambda表達式確實極大的簡化了我們的代碼,提高了編碼的效率,流計算更是使數據的運算變得高效快捷,也增加了代碼的可(zhuang)讀(bi)性。如今java14都出來了,希望在空余時間也能多去了解一下新版本的新特性,而不能老是抱著(你發任你發,我用java8)的心態去學習,畢竟技術的更新迭代是極快的。

到此這篇關于使用java8的方法引用替換硬編碼的示例代碼的文章就介紹到這了,更多相關java8的方法引用替換硬編碼內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/-tang/p/13633732.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 天天色宗合| 久久金品 | 麻豆一二区 | 二区视频 | 久久精品亚洲一区二区 | 久热久操 | 久久亚洲精品国产 | 久久人人97超碰国产公开结果 | 在线观看免费毛片视频 | 红杏网站永久免费视频入口 | 欧美精品久久久久久久久久 | 大学生一级毛片在线视频 | 国产精品久久久久久久久久电影 | 黄网免费看 | 日韩电影一区二区三区 | 久久久久北条麻妃免费看 | 免费观看三级毛片 | 亚久久 | 亚洲一区二区免费 | 午夜精品久久久久久毛片 | 亚洲乱码精品久久久久 | 久久精品视频日本 | 成人综合免费视频 | 在线免费日韩 | 妇子乱av一区二区三区 | 欧美一级黄色免费 | 性盈盈盈影院 | 色av成人天堂桃色av | 免费男女视频 | 国产亚洲精品久久久久5区 日韩一级片一区二区三区 国产精品久久久久av | 亚洲热线99精品视频 | 亚洲视频在线免费看 | 久久99综合| 福利在线播放 | 最新久久免费视频 | 综合精品 | 最近日本电影hd免费观看 | 中文字幕在线观看网址 | 亚洲精品久久久久久久久久 | 毛片视频免费观看 | 国产一区免费在线 |