这是Effective Java第七章的总结, 讲Lambdas和Streams这两个在Java8中经常使用的特性. 项目链接JavaLab.
Item 42: Prefer lambdas to anonymous classes
对匿名类, 可以用lambda简化写法. lambda的限制是只能替换函数式对象/不能保证序列化和反序列化的正确性, 还有一点, 如果lambda写的过长, 也会影响可读性.
Item 43: Prefer method references to lambdas
灵活运用method references和lambdas, 哪个写法可读性高用哪个, 我自己使用中大多数情况还是prefer method references, 因为可以一下就定位执行方法的来源是哪个类. 书中总结了如下五种可以来回替换的类型.
Method Ref Type | Example | Lambda Equivalent |
---|---|---|
Static | Integer::parseInt | str -> Integer.parseInt(str) |
Bound | Instant.now()::isAfter | Instant then = Instant.now(); t -> then.isAfter(t) |
Unbound | String::toLowerCase | str -> str.toLowerCase() |
Class Constructor | TreeMap<K,V>::new | () -> new TreeMap<K,V> |
Array Constructor | int[]::new | len -> new int[len] |
Item 44: Favor the use of standard functional interfaces
有了函数式编程的加持, 写api的时候就可以用各种functional interfaces
. 大多数情况下不用子基写, 直接使用java.util.function
包中的就ok. 6个基本的函数式接口如下. 他们都有int/long/double的版本, 方法名就是前缀加数据类型. 具体使用时看包下有哪些接口最直观.
Interface | Function Signature | Example |
---|---|---|
UnaryOperator | T apply(T t) | String::toLowerCase |
BinaryOperator | T apply(T t1, T t2) | BigInteger::add |
Predicate | boolean test(T t) | Collection::isEmpty |
Function<T,R> | R apply(T t) | Arrays::asList |
Supplier | T get() | Instant::now |
Consumer | void accept(T t) | System.out::println |
Item 45: Use streams judiciously
streams和写循环需要trade off, streams让代码短了, 但是可读性可能差了, 通过一定的helper method可以帮助提升可读性. 因为stream过程中的值是拿不到的, 会对debug造成困扰(虽然idea有stream debug工具). 书中列举了几个stream用起来很舒适的场景:
- Uniformly transform sequences of elements
- Filter sequences of elements
- Combine sequences of elements using a single operation(for example to add them, concatenate them, or compute their minimum)
- Accumulate sequences of elements into a collection, perhaps grouping them by some common attribute
- Search a sequence of elements for an element satisfying some criterion
Item 46: Prefer side-effect-free functions in streams
对同一个逻辑, 虽然可以写不同的stream实现, 但是要记住我们是在用函数式编程的思想. 比如forEach
方法应该是用来展示stream的结果, 而不是用来在stream中计算, 我们需要的是一个stream的输入输出, 而不是过程中每个元素的行为. 除此之外书中介绍了toList/toSet/toMap/groupingBy/joining
, 其中toMap有个坑, 在书中也介绍了.
Item 47: Prefer Collection to Stream as a return type
在Java8, Stream和Iterator的相互转换不是容易的事情. 所以当我们写的返回返回一个sequence时, 最好用Collection的实现, 这样在使用的地方既可以用stream处理, 也可以用for-each处理. Collection的限制是size()
的返回值是int, 所以这个方法最大只能返回Integer.MAX_VALUE
, 当然具体能不能存超过这个值的数字, 还是要看具体的实现.
Item 48: Use caution when making streams parallel
用parallel()
来提高stream的性能时需要极其谨慎, 极有可能出错. 比如Stream.iterate()
这种无法被并行的stream, 并行只会对`ArrayList/HashMap/HashSet/ConcurrentHashMap/array/int range/long ranges这种可以被轻易切分, 而且能快速定位引用的模块有好的效果.
comments powered by Disqus