欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2020年09月09日 10:21:59   作者:我恰芙蓉王  
這篇文章主要介紹了使用java8的方法引用替換硬編碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

背景

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

原代碼

工具類

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";

  /**
   * 功能描述: 公用統(tǒng)計小計方法
   *
   * @param list  原數(shù)據(jù)列表集合
   * @param fields 運算的屬性數(shù)組
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統(tǒng)計好的對象
   **/
  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;
  }

  /**
   * 功能描述: 公用統(tǒng)計小計方法
   *
   * @param list  原數(shù)據(jù)列表集合
   * @param fields 運算的屬性數(shù)組
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統(tǒng)計好的對象
   **/
  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;
  }

  /**
   * 功能描述: 公用統(tǒng)計小計方法
   *
   * @param list  原數(shù)據(jù)列表集合
   * @param fields 運算的屬性數(shù)組
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統(tǒng)計好的對象
   **/
  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 被加數(shù)
   * @param v2 加數(shù)
   * @return 兩個參數(shù)的和
   */
  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 被加數(shù)
   * @param v2 加數(shù)
   * @return 兩個參數(shù)的和
   */
  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();
  }
}

實體類

@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;
}

測試

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("總計數(shù)據(jù)為 :" + orderTotal);

  Phone phoneTotal = totalCalculationForBigDecimal(phoneList, "cost", "price");
  System.out.println("總計數(shù)據(jù)為 :" + phoneTotal);
}

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

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

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

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

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

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

今天就順著這個方向去找了一下實現(xiàn)的方法,把代碼優(yōu)化了部分,如下:

優(yōu)化后

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

@FunctionalInterface
public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {

}

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

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方法的方法引用返回對應(yīng)的Field
   *
   * @param function
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 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對應(yīng)的Getter方法名
       */
      SerializedLambda serializedLambda = (SerializedLambda) method.invoke(function);
      //獲取get方法的方法名
      String getter = serializedLambda.getImplMethodName();
      //獲取屬性名
      String fieldName = StringUtils.uncapitalize(getter.replace(GET, ""));
      /**
       * 3.獲取的Class是字符串,并且包名是“/”分割,需要替換成“.”,才能獲取到對應(yīng)的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點都規(guī)避了,將原來冗余的多個方法精簡成一個 totalCalculation ,通過 methodMap 對象將get,set方法緩存(但此緩存還有優(yōu)化的空間,可以將方法中的緩存對象提到tomcat內(nèi)存或redis中),通過動態(tài)獲取字段類型來實現(xiàn)不同類型的累加運算

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 {

  /**
   * 功能描述: 公用統(tǒng)計小計方法
   *
   * @param list   原數(shù)據(jù)列表集合
   * @param functions 參與運算的方法引用
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 2020年05月12日 17:50:09
   * @return: org.apache.poi.ss.formula.functions.T  返回統(tǒng)計好的對象
   **/
  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);
            //調(diào)用x參數(shù)t屬性的get方法
            Object xValue = getMethod.invoke(x);
            //調(diào)用y參數(shù)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  加數(shù)
   * @param v2  被加數(shù)
   * @param clazz 參數(shù)的class類型
   * @創(chuàng)建人: 我恰芙蓉王
   * @創(chuàng)建時間: 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());
  }

}

測試實體類

@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {

  //名字
  private String name;

  //年齡
  private Integer age;

  //存款
  private BigDecimal money;

  //身高
  private Double height;
}

調(diào)用

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("總計數(shù)據(jù)為 :" + total);
}

總結(jié)

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

到此這篇關(guān)于使用java8的方法引用替換硬編碼的示例代碼的文章就介紹到這了,更多相關(guān)java8的方法引用替換硬編碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 10個微妙的Java編碼最佳實踐

    10個微妙的Java編碼最佳實踐

    這篇文章讓我與你分享10個微妙的Java編碼最佳實踐,需要的朋友可以參考下
    2017-11-11
  • Jdk中沒有jre文件夾怎么辦?如何解決?

    Jdk中沒有jre文件夾怎么辦?如何解決?

    這篇文章主要介紹了Jdk中沒有jre文件夾怎么辦?如何解決的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java程序開發(fā)環(huán)境配置圖文教程

    Java程序開發(fā)環(huán)境配置圖文教程

    這篇文章主要為大家詳細介紹了Java程序開發(fā)環(huán)境配置圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • java數(shù)學(xué)歸納法非遞歸求斐波那契數(shù)列的方法

    java數(shù)學(xué)歸納法非遞歸求斐波那契數(shù)列的方法

    這篇文章主要介紹了java數(shù)學(xué)歸納法非遞歸求斐波那契數(shù)列的方法,涉及java非遞歸算法的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • Java數(shù)據(jù)類型之細講char類型與編碼關(guān)系

    Java數(shù)據(jù)類型之細講char類型與編碼關(guān)系

    這幾天一直在復(fù)習(xí)Java基礎(chǔ)知識,特地寫了一篇文章來做一下筆記,文中有非常詳細的圖文示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • Java生成唯一ID的三種方法總結(jié)

    Java生成唯一ID的三種方法總結(jié)

    單機環(huán)境下,可以使用AtomicLong來生成唯一ID;而在需要非純數(shù)字形式的場景中,可以通過UUID結(jié)合哈希函數(shù)如MD5或SHA-1轉(zhuǎn)換成數(shù)字,但需注意哈希碰撞的低概率風(fēng)險;對于分布式系統(tǒng),模擬Snowflake算法是一種復(fù)雜但有效的方法,每種方法都有其適用場景和潛在問題
    2024-09-09
  • Spring?DI依賴注入過程解析

    Spring?DI依賴注入過程解析

    依賴注入是由“依賴”和“注入”兩個詞匯組合而成,那么我們再一次順藤摸瓜,分別分析這兩個詞語,這篇文章主要介紹了Spring?DI依賴注入詳解,需要的朋友可以參考下
    2022-11-11
  • java堆排序原理與實現(xiàn)方法分析

    java堆排序原理與實現(xiàn)方法分析

    這篇文章主要介紹了java堆排序原理與實現(xiàn)方法,結(jié)合實例形式分析了java堆排序的相關(guān)原理、實現(xiàn)方法與操作注意事項,需要的朋友可以參考下
    2018-12-12
  • 深入理解hibernate的三種狀態(tài)

    深入理解hibernate的三種狀態(tài)

    本篇文章主要介紹了深入理解hibernate的三種狀態(tài) ,主要包括了transient(瞬時狀態(tài)),persistent(持久化狀態(tài))以及detached(離線狀態(tài)),有興趣的同學(xué)可以了解一下
    2017-05-05
  • 如何基于spring security實現(xiàn)在線用戶統(tǒng)計

    如何基于spring security實現(xiàn)在線用戶統(tǒng)計

    這篇文章主要介紹了如何基于spring security實現(xiàn)在線用戶統(tǒng)計,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06

最新評論