評審程式碼時,這樣寫就不會被懟了

a_wei發表於2019-12-23

在JDK版本普遍升級到8之後,最近參與了幾次程式碼評審,好多人對JDK8中的用法不是特別熟熟悉,用的不對或者乾脆用錯的常有,程式碼評審時經常被說到,這裡整理一波實用的技巧,希望大家舉一反三,有所收穫。
廢話不多說,直接乾貨,覺得口渴文章底部有水(文字總結)

判空操作
 //最佳化之前  
 if (obj != null){
 }
 //最佳化之後
 if (Optional.ofNullable(obj).isPresent()){
 }
判空異常操作
 //最佳化之前  
 if (obj == null){
    throw new .....
 }
 //最佳化之後
Optional.ofNullable(obj).isPresent().orElseThrow(() ->new RuntimeException(""));
返回非空值
 //最佳化之前
 if list == null{
    return new ArrayList();
 }
 return list;
 //最佳化之後
 return Optional.ofNullable(list).orElse(new ArrayList<>()).get()
求最大值最小值
Integer max = Stream.of(1,2,3,4,5).max(Integer::compareTo).get();
Integer min = Stream.of(1,2,3,4,5).min(Integer::compareTo).get();
去重操作
//最佳化前
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(1);
Set<Integer> set = new HashSet(list);
//最佳化後
List<Integer> temp =list.distinct().collect(Collectors.toList());
集合判空遍歷操作
//最佳化前
if (list == null){
    return
}
for (String s : list){
}

//最佳化後
Optional.ofNullable(list).orElse(new ArrayList<>()).stream().forEach()
匿名內部類
//最佳化前
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Java8 ");
    }
}).start();
//最佳化後
new Thread(() -> System.out.println("Java8!"));
規約計算
//基於資料流的方式,將流裝載成相應的 SummaryStatistics進行歸約計算,可以實現更多的操作;
IntSummaryStatistics stats = list.stream().mapToInt(i -> i). summaryStatistics();
int max = stats.getMax();        //獲取最大值
int min = stats.getMin();        //獲取最小值
double sum =  stats.getSum();    //獲取總值
double avg = stats.getAverage();  //獲取平均值
long count = stats.getCount();     //獲取總數量
排序
//升序
List<Integer> temp1 = Stream.of(2,1,3,5,0,6).sorted().collect(Collectors.toList());
//自己制定排序方式
List<Integer> temp2 = Stream.of(2,1,3,5,0,6)
.sorted((x,y) -> Integer.compare(x,y))        
.collect(Collectors.toList());
求和
//最佳化前
List<Integer> list  = new ArrayList();
Integer sum = 0;
for (Integer i : list){
   sum = sum + i;
}
//最佳化後
//方式一
sum = list.stream().mapToInt(Integer::intValue).sum();
//還有mapToDouble,mapToLong
//方式二
sum = list.stream().reduce((x,y) -> x+y);
過濾
//最佳化之前
List<Integer> list  = new ArrayList();
List<Integer> newList = new ArrayList();
for (Integer i : list){
    if (i % 2 ==0){
        newList.add(i);
    }
}
//最佳化之後
newList = list.stream().filter(i -> i % 2 ==0).collect(Collectors.toList());
分組歸類
//最佳化之前
List<Student> list= Arrays.asList(
        new Student(1,"one","zhao"),
        new Student(2,"one","qian"),
        new Student(3,"two","sun")
);
//1.1根據某個屬性分組計數
Map<String,Long> map = new HashMap();
for (Student s : list){
    if(map.containsKey(s.getGroupId())){
        Long l = map.get(s.getGroupId());
        map.put(s.getGroupId(),l+1);
    }else{
        map.put(s.getGroupId(),1L);
    }
}
//最佳化之後
map=list.stream().collect(Collectors.groupingBy(Student::getGroupId,
Collectors.counting()));
定義函式式方法
//functionTest入參接受一個函式,這個函式入參是Integer,出參是String
public void functionTest(Function<Integer,String> apply, List<Integer> nums){
    nums.forEach(n ->{
        String result = apply.apply(n);
        System.out.println(result);
    });
}
functionTest(n ->{return String.valueOf(n);},Lists.newArrayList(1, 2, 3, 4));
並行流計算
//最佳化之前
List<String> list = new ArrayList();
for(String no : list){
    //下發
    down(no)
}
//最佳化之後,parallel是多個執行緒併發的,這個底層是fork-join,執行緒數和cpu核數相等
//這種寫法應該防止因parallel的執行緒數耗盡,導致後面的請求的排隊,從而超時,甚至雪崩,壓跨伺服器
list.stream().parallel().forEach(no -> down(no));
List轉換Map,key衝突處理

List<String> list12 = new ArrayList();
list12.stream().collect(Collectors.toMap(
        s -> {return s;}, //map的key
        s -> {return 1;}, //map的value
        (Integer src,Integer des) ->{ //當key衝突時,value相加
            return src+des;
        }
));
讀取檔案
final Path path = new File( "A:\\1.txt" ).toPath();
//必須放入try with resource語法,這個流是需要的關閉的,或者try cache finally手動關閉流
try(Stream< String > lines = Files.lines(path)){
    lines.onClose(()->{ System.out.println("down");}).forEach( System.out::println);
}catch (Exception e){
}
//如果出現下面的異常,看看檔案編碼,指定成utf-8
//當輸入位元組序列對於給定 charset 來說是不合法的,或者輸入字元序列不是合法的 16 位 Unicode 序列時,丟擲此經過檢查的異常
java.nio.charset.MalformedInputException: Input length = 1
擷取流的前N個元素

List<String> list = Arrays.asList("hello","I","love","you");
List<String> temp = list.stream()
                          .limit(3)
                          .collect(Collectors.toList());
跳過流的前N個元素
List<String> list = Arrays.asList("hello","I","love","you");
List<String> temp = list.stream()
                          .skip(2)
                          .collect(Collectors.toList());
匹配符合條件的第一個元素
List<String> list = Arrays.asList("hello","hello","hello","hello");
//返回配到的元素
String str = list.stream().filter( s -> {return ("hello").equals(s);}).findFirst();
匹配任何一個則返回
List<String> list = Arrays.asList("hello","i","love","you");
//匹配到love時就返回true,否則返回返回false
boolean falg = list.stream().anyMatch(s -> s.equals("love"));
匹配所有
List<String> list = Arrays.asList("hello","hello","hello","hello");
//只有list中所有的字串都為hello才返回true,否則返回false
boolean falg = list.stream().allMatch(s -> s.equals("hello"));
總結一下Stream流的特點

總的來說,Stream流操作是對資料來源進行一系列處理最終得到一個目標結果,資料流可以是有限的,也可以是無限的,這個處理過程整體分為兩步
中間操作
這個操作返回的還是一個流,對資料經過某種操作後,再透過流進行下一個操作,就比如流水線上的加工程式,這個操作對資料的處理分別為無狀態處理和有狀態處理,所謂無狀態就是對每一個資料都是單獨處理,資料沒有依賴關係,有狀態操作處理時資料之間會有依賴關係,比如max()操作,資料之間會進行比較。
終端操作
流只能有一個終端操作,這個操作完成後,資料就已經是死資料了,得到了結果,流已經被使用完了,相當於流水線上最後一步加工完成後已經成為一個產品了,這個操作歸為短路和非短路兩類操作,短路操作指的流中的資料會在一個條件下終止,比如findFirst(),在所有資料中匹配到第一個符合條件的資料就終止,而非短路操作時所有資料都會遍歷,比如sum(),所有資料累加成為最後結果

評審程式碼時,這樣寫就不會被懟了,乾貨

Stream的一些特性

  1. 無儲存
  2. 函數語言程式設計,能夠減少大量程式碼
  3. 延遲執行,也叫做惰性執行
  4. 可消費(只會被消費一次)
  5. 可讀性好(但剛剛入門可能難以理解)

評審程式碼時,這樣寫就不會被懟了,乾貨

本作品採用《CC 協議》,轉載必須註明作者和本文連結
那小子阿偉

相關文章