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