使用JDK8新特性重構你的代碼

lambda 表達式算法

 當一個接口只有一個方法的時候均可以使用lambda 表達式代替 這種稱爲函數接口能夠用 @FunctionalInterface 修飾數據庫

// 使用匿名類的方式 
 new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
   });
 //使用lambda 表達式方式 
 new Thread(()-> System.out.print("hello") );

 

  • lambda 表達式多種形式設計模式

1) ActionListener listener= event-> System.out.print("hello"); 
 // event表示方法的參數括號 lambda表達式返回能夠當作是一個函數的引用
2) BinaryOperator<Long> add = (x,y)->x+y;    
// 一樣若是有2個參數能夠這樣表示
3) BinaryOperator<Long> add =(Long x,Long y)-> { x+y; System.out.print("hello"); }  
// 一樣 咱們能夠加上具體的參數類型  若是是多行須要加 {}

 

  • 使用lambda表達式實現設計模式 api

      這裏咱們實現一個解壓算法的策略模式app

// 定義好接口
@FunctionalInterface
public interface  Compression{
    public OutputStream compress(OutputStream data) throws IOException;
}
// 定義調用類 
class  Compressor {
    private   Compression strategy;
    public  Compressor(Compression starategy){
        this.strategy =    starategy;
    }
    public void compress() throws IOException {
        strategy.compress(new FileOutputStream(new File("test.txt")));
    }
}
// 傳統的作法 定義好實現類 lambda省略這個步驟
class  ZipCompression implements  Compression{
    @Override
    public OutputStream compress(OutputStream data) throws IOException {
        return new ZipOutputStream(data );
    }
}
class  GZipCompression implements  Compression{
    @Override
    public OutputStream compress(OutputStream data) throws IOException {
        return new GZIPOutputStream(data );
    }
}
public static void main(String[] args) throws IOException {
        //傳統方式
        new Compressor(new GZipCompression()).compress(); ;
        new Compressor(new ZipCompression()).compress(); ;
         //lambda方式 
        //咱們能夠看到用lambda 方式徹底不用實現 ZipCompression GZipCompression類了
        new Compressor(GZIPOutputStream::new).compress();
        new Compressor(ZipOutputStream::new).compress();
}

Stream ide

stream API 多是JDK8中最大的改變 改變咱們操做流的習慣函數

使用集合時調用 .stream()  轉爲流操做模式 JDK8的集合 都帶有這個方法 (Map沒有)                                                         下面咱們使用stream API重構咱們的集合操做ui

 隨機找一段 項目中的代碼進行重構this

  •   使用streamspa

// 這段代碼是一個model list 轉爲 ztree list 的方法
public List<ZTree> getZTree() {
 List<ZTree> list = Lists.newArrayList();
   for (Res r : super.findAll()) {
   ZTree zt = new ZTree(r.getId(), r.getName(), r.getPid());
   if (zt.id == 0) zt.setDisCheck(true);
   list.add(zt);
}
 return list;
}

 

public List<ZTree> getZTree() {
return super.findAll()
            .stream()
            .map(this::getZtree())
            .collect(Collectors.toList());
}

public Ztree getZtree(Model r){
    ZTree zt = new ZTree(r.getId(), r.getName(), r.getPid());
    if (zt.id == 0) zt.setDisCheck(true);
    return zt;
}

   代碼解析 

.map() 接受一個lambda 表達式 對集合類型進行轉換 這裏是對數據庫查詢到的對象 轉化爲 ZTree對象
.collect() 最後轉化爲新的集合

 

  • 重構和定製收集器

   下面咱們來看一個更復雜的重構咱們的代碼

    同時使用到了自定義的收集器

   咱們須要把 一個Song的集合 的名字進行格式化處理 

class Song {
    private String name;
    public long length;

    public String getName() {
        return name;
    }
}

/**
 * 格式化  v1.0
 * 咱們原有的代碼是這樣的
 * 看起來好像沒啥問題
 * 仍是好像不太方便重用
 * @param list
 * @return
 */
public String getName(List<Song> list) {

    StringBuffer sb = new StringBuffer("[");

    for (Song song : list) {
        if (sb.length() > 1) sb.append(",");
        sb.append(song.getName());
    }
    return sb.toString();
}


/**
 * 格式化  v2.0
 * <p>
 * 只是用了jdk8的特性
 * 可是
 * 好像並無太大改進
 *
 * @param list
 * @return
 */
public String getName2(List<Song> list) {

    StringBuffer sb = new StringBuffer("[");

    list.stream()
            .map(Song::getName)
            .forEach(name -> {
                if (sb.length() > 1) sb.append(",");
                sb.append(name);
            });

    return sb.toString();
}

/**
 * 格式化  v3.0
 * <p>
 *
 * foreach的操做彷佛太過笨重
 * 咱們使用reduce 完成這個過程
 *
 * 可是彷佛讓代碼更糟糕啦
 *
 * @param list
 * @return
 */
public String getName3(List<Song> list) {

    return list.stream()
            .map(Song::getName)
            .reduce(new StringBuilder(), (builder, name) -> {
                if (builder.length() > 0) builder.append(",");
                builder.append(name);
                return builder;
            }, (left, right) -> left.append(right))
            .insert(0, "[").append("]").toString();
}
/**
 * 格式化 v4.0
 *
 *咱們用StringCombiner
 * 來代替原先的操做
 *來隱藏雜亂無章的細節
 *
 * 看起來是否是好了點
 *
 * @param list
 * @return
 */
public String getName4(List<Song> list) {

    return list.stream().map(Song::getName)
            .reduce(new StringCombiner(",", "[", "]"),
                    StringCombiner::add,
                    StringCombiner::merge).toString();

}

class StringCombiner {

    private final String delim;
    private final String prefix;
    private final String suffix;
    private final StringBuilder builder;

    public StringCombiner(String delim, String prefix, String suffix) {
        this.delim = delim;
        this.prefix = prefix;
        this.suffix = suffix;
        builder = new StringBuilder();
    }

    public StringCombiner add(String element) {
        if (areAtStart()) {
            builder.append(prefix);
        } else {
            builder.append(delim);
        }
        builder.append(element);
        return this;
    }

    private boolean areAtStart() {
        return builder.length() == 0;
    }

    public StringCombiner merge(StringCombiner other) {
        if (other.builder.length() > 0) {
            if (areAtStart()) {
                builder.append(prefix);
            } else {
                builder.append(delim);
            }
            builder.append(other.builder, prefix.length(), other.builder.length());
        }
        return this;
    }

    @Override
    public String toString() {
        if (areAtStart()) {
            builder.append(prefix);
        }
        builder.append(suffix);
        return builder.toString();
    }

}

 

/**
 * 格式化 v5.0
 *
 * 以前的代碼看起來不錯了
 * 可是還不能在程序中重用
 * 咱們自定義一個收集器
 * 這樣看起來是否是更好了
 *
 * @param list
 * @return
 */
public String getName5(List<Song> list) {

    return  list.stream().map(Song::getName).collect(new StringCollector(".","[","]"));

}

class StringCollector implements Collector<String, StringCombiner, String> {

      private   final Set<Characteristics> characteristics = Collections.emptySet();

      private final String delim;
      private final String prefix;
      private final String suffix;

      public StringCollector(String delim, String prefix, String suffix) {
          this.delim = delim;
          this.prefix = prefix;
          this.suffix = suffix;
      }

      public Supplier<StringCombiner> supplier() {
          return () -> new StringCombiner(delim, prefix, suffix);
      }
   
      public BiConsumer<StringCombiner, String> accumulator() {
          return StringCombiner::add;
      }
   
      public BinaryOperator<StringCombiner> combiner() {
          return StringCombiner::merge;
      }


      public Function<StringCombiner, String> finisher() {
          return StringCombiner::toString;
      }
    
 
      public Set<Characteristics> characteristics() {
          return characteristics;
      }

 並行計算

 在多核cpu的時代並行計算能很大的提高程序的速度

 在stream api中使用.parallelStream();替換stream()就能夠直接擁有並行計算的能力

 固然也不能隨便使用基本上要注意幾點

 1)處理的數據量 若是過小處理管道花費的時間遠大於單線程的時間
 2)單核cpu 就沒有必要使用了
 3)單元處理開銷在每一個元素身上處理的時間越長並行越有意義

 

好了你們都學會了麼 趕忙用起來吧 

 

參考資料 Java 8 Lambdas Functional Programming for the Masses      

相關文章
相關標籤/搜索