一、语法糖
-
字符串连接的例子
-
“abc” + “123” + “31553我w# ! ! !”
-
// jad -p SugarDemo //The class file version is 52.0 (only 45.3, 46.0 and 47.0 are supported) // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://kpdus.tripod.com/jad.html // Decompiler options: packimports(3) // Source File Name: SugarDemo.java package com.zhong.test_11; import java.io.PrintStream; public class SugarDemo { public SugarDemo() { } public static void main(String args[]) { String str1 = "123"; String str2 = "abc"; String str3 = null; String str4 = (new StringBuilder()).append(str1).append(str2).append(str3).toString(); System.out.println(str4); } }
-
编程时使用 “+” 连接字符串并不是最终的语法,最终实际上是利用 StringBuilder 对象的 append() 链式方法来实现字符串的连接操作。因此,用 “+” 连接字符串的语法就是语法糖。
-
-
什么是语法糖
- 就是在语言的基本语法上添加新的语法,新语法对基本语法不会造成改变,但是它可以让编程变得更加便捷,令代码的可读性得到增强。新语法是对基本语法的封装。
- jvm不识别语法糖,但是编译器能够识别,语法糖在编译时会被解溏,把语法糖转换为基本语法。在 javac 程序中,有一个方法 deSugar() 用来解糖。解糖的反操作是加糖,反编译工具没有加糖的功能,因此能够看出来语法糖的基本语法实现。
-
大多数常见的语言都有语法糖,C,C++,C语言等,java 属于低糖语言。
-
java 常见的语法糖
- 字符串连接,泛型,字面量,增强 for 循环,装箱拆箱,方法的可变参数,try-with-resource语法,内部类等。
- 以上都可以通过反编译工具进行反编译,看到基本语法的实现过程。
二、流式编程
- Stream 就是流,它与 IO 中的流完全不同。
-
流式编程是基于 lambda 表达式及多核CPU结构的一种编程方式,也是 jdk1.8 中最典型的新特征之一。
-
流式编程主要解决集合操作的形式化的特点。集合操作中最常见的是遍历操作,遍历必须先得到迭代器对象,然后再通过迭代器逐一的取出元素,再进行处理。
流式编程主要是可以剔除集合遍历过程中形式化的代码,只关注 “做什么” 的事情。
-
jdk1.8 中新增的支持 lambda 和流式编程的 API
(1)工具包中新加了 stream 子包,该包中的 Interface Stream 接口表示类型,其中的各种方法就是执行流式操作的一些各种功能的方法,这是流式编程的核心 API 。
(2)工具包中新加了 function 子包,里面全部是函数式接口,其中的大部分 API 都用来支持流式编程。
(3)Collection 这个集合框架的顶层接口,它新加了一个 stream() 方法,可以把集合对象转换为流对象。
-
流式编程的一般步骤
- 流式编程让遍历集合变得更加简单,因此它有一套规定的编程方式。
-
流式编程与 lambda 表达式的关系
- 流式编程的中间操作和结果操作的方法参数都是函数式接口,因此使用流式编程建议使用 lambda 表达式。
-
流式编程的具体方法
- 把集合转换为流对象,在集合上调用 stream() 方法。
- 把数组转换为流对象,调用 Stream.of(数组) 静态方法。
- 中间操作,包含有多种操作,比如过滤,map,disinct,limit,skip等。中间操作并不会改变原有的集合内容。
- 结果操作,在中间操作的基础上得到的最终结果。比如 forEach,collect,max,min 等方法,它们要么返回一个结果,要么就没有返回值,不会返回 Stream 对象。
-
流式编程的执行过程
- 所有的中间操作并不会马上执行,一定是在开始执行最后结果时才开始实质性的中间处理。这称为延迟操作,或懒加载。
三、方法引用
- 是使用 lambda 表达式时的一种更加简洁的方式。
-
流式编程中的排序方法 sorted(),forEach() 方法为例,使用方法引用的语法来实现。
package com.zhong.test_11; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Stream; public class SugarDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); Collections.addAll(list, "abc", "ABC", "xyz", "Xyz", "123", "345"); Stream<String> stream = list.stream(); //中间操作 //过滤操作,取部分元素,给元素添加新的内容,进行最后的处理 stream.filter((s) -> s.endsWith("z")).limit(3).map((s) -> s + "9").forEach(System.out::println); } }
-
方法引用是 jdk1.8 与 lambda 表达式和流式编程相关的一种新的语法。它是难点。
-
使用方法引用的前提
(1)lambda 表达式的主体(->后的部分)只有一个表达式;
(2)执行的主体有一个已存在的方法(无论类和对象)来完成;
(3)基本要求,表达式的参数与返回值要与已存在的方法相同;
四、什么时候使用流式编程
- Stream 中提供了多种中间操作和结果操作,如果是对集合进行遍历,在遍历过程中的对元素的处理方式与 Stream 中的操作是一致的,就首先考虑使用流式编程,让代码更简洁更优雅,也更能体现程序员与时俱进的优点。
- 在流式编程中,可以用到 lambda 表达式的位置都可以结合方法引用的前提来考虑是否可以使用方法引用的语法。