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