Java 8里面lambda的最佳实践(1)
Java 8里面lambda的最佳实践(1)
Java 8已经推出一段时间了,越来越多开发人员选择升级JDK,这条热门动弹里面看出,JDK7最多,其次是6和8,这是好事!
在8 里面Lambda是最火的主题,不仅仅是因为语法的改变,更重要的是带来了函数式编程的思想,我觉得优秀的程序员,有必要学习一下函数式编程的思想以开阔思路。所以这篇文章聊聊Lambda的应用场景,性能,也会提及下不好的一面。
Java为何需要Lambda
1996年1月,Java 1.0发布了,此后计算机编程领域发生了翻天覆地的变化。商业发展需要更复杂的应用,大多数程序都跑在更强大的装备多核CPU的机器上。带有高效运行期编 译器的Java虚拟机JVM)的出现,使得程序员将精力更多放在编写干净、易于维护的代码上,而不是思考如何将每一个CPU时钟、每一字节内存物尽其 用。
多核CPU的出现成了“房间里的大象”,无法忽视却没人愿意正视。算法中引入锁不但容易出错,而且消耗时间。人们开发了 java.util.concurrent包和很多第三方类库,试图将并发抽象化,用以帮助程序员写出在多核CPU上运行良好的程序。不幸的是,到目前为 止,我们走得还不够远。
那些类库的开发者使用Java时,发现抽象的级别还不够。处理大数据就是个很好的例子,面对大数据,Java还欠缺高效的并行操作。Java 8允许开发者编写复杂的集合处理算法,只需要简单修改一个方法,就能让代码在多核CPU上高效运行。为了编写并行处理这些大数据的类库,需要在语言层面上 修改现有的Java:增加lambda表达式。
当然,这样做是有代价的,程序员必须学习如何编写和阅读包含lambda表达式的代码,但是,这不是一桩赔本的买卖。与手写一大段复杂的、线程安全 的代码相比,学习一点新语法和一些新习惯容易很多。开发企业级应用时,好的类库和框架极大地降低了开发时间和成本,也扫清了开发易用且高效的类库的障碍。
如果你还未接触过Lambda的语法,可以看这里。
Lambda的应用场景
你有必要学习下函数式编程的概念,比如函数式编程初探,但下面我将重点放在函数式编程的实用性上,包括那些可以被大多数程序员理解和使用的技术,我们关心的如何写出好代码,而不是符合函数编程风格的代码。
1.使用() -> {} 替代匿名类
现在Runnable线程,Swing,JavaFX的事件监听器代码等,在java 8中你可以使用Lambda表达式替代丑陋的匿名类。
- //Before Java 8:
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Before Java8 ");
- }
- }).start();
- //Java 8 way:
- new Thread(() -> System.out.println("In Java8!"));
- // Before Java 8:
- JButton show = new JButton("Show");
- show.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- System.out.println("without lambda expression is boring");
- }
- });
- // Java 8 way:
- show.addActionListener((e) -> {
- System.out.println("Action !! Lambda expressions Rocks");
- });
2.使用内循环替代外循环
外循环:描述怎么干,代码里嵌套2个以上的for循环的都比较难读懂;只能顺序处理List中的元素;
内循环:描述要干什么,而不是怎么干;不一定需要顺序处理List中的元素
- //Prior Java 8 :
- List features = Arrays.asList("Lambdas", "Default Method",
- "Stream API", "Date and Time API");
- for (String feature : features) {
- System.out.println(feature);
- }
- //In Java 8:
- List features = Arrays.asList("Lambdas", "Default Method", "Stream API",
- "Date and Time API");
- features.forEach(n -> System.out.println(n));
- // Even better use Method reference feature of Java 8
- // method reference is denoted by :: (double colon) operator
- // looks similar to score resolution operator of C++
- features.forEach(System.out::println);
- Output:
- Lambdas
- Default Method
- Stream API
- Date and Time API
3.支持函数编程
为了支持函数编程,Java 8加入了一个新的包java.util.function,其中有一个接口java.util.function.Predicate是支持Lambda函数编程:
- public static void main(args[]){
- List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
- System.out.println("Languages which starts with J :");
- filter(languages, (str)->str.startsWith("J"));
- System.out.println("Languages which ends with a ");
- filter(languages, (str)->str.endsWith("a"));
- System.out.println("Print all languages :");
- filter(languages, (str)->true);
- System.out.println("Print no language : ");
- filter(languages, (str)->false);
- System.out.println("Print language whose length greater than 4:");
- filter(languages, (str)->str.length() > 4);
- }
- public static void filter(List names, Predicate condition) {
- names.stream().filter((name) -> (condition.test(name)))
- .forEach((name) -> {System.out.println(name + " ");
- });
- }
- Output:
- Languages which starts with J :
- Java
- Languages which ends with a
- Java
- Scala
- Print all languages :
- Java
- Scala
- C++
- Haskell
- Lisp
- Print no language :
- Print language whose length greater than 4:
- Scala
- Haskell
4.处理数据?用管道的方式更加简洁
Java 8里面新增的Stream API ,让集合中的数据处理起来更加方便,性能更高,可读性更好
假设一个业务场景:对于20元以上的商品,进行9折处理,最后得到这些商品的折后价格。
- final BigDecimal totalOfDiscountedPrices = prices.stream()
- .filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)
- .map(price -> price.multiply(BigDecimal.valueOf(0.9)))
- .reduce(BigDecimal.ZERO,BigDecimal::add);
- System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);
想象一下:如果用面向对象处理这些数据,需要多少行?多少次循环?需要声明多少个中间变量?
关于Stream API的详细信息,可以查看我之前写的文章 。

用户点评