JAVA 8 新特性
1. Lambda 表达式
1.1 简介
Lambda 是一个匿名函数,通过 lambda 操作符 ->
分成左右两部分:
- 左侧:lambda 表达式的参数列表;
- 右侧:lambda 表达式中所需要执行的功能,即 lambda 体。
Lambda 表达式需要函数式接口支持,接口中只有一个抽象方法的接口为函数式接口,可以使用注解 @FunctionInterface
修饰,通过该注解可检验是否为函数式接口,比如:
// 非函数式接口,因为不止一个抽象方法
public interface xxx<T> {
public boolean test(T t);
public boolean test1(T t);
}
// 函数式接口,使用此注解后,如果有多个方法,那么会报错
@FunctionInterface
public interface xxx<T> {
public boolean test(T t);
}
1.2 Lambda 表达式多种语法格式
-
格式一:无参数、无返回值。
() -> System.out.println("Hello Lambda");
比如:
public class TestLambd1 { @Test public void test() { Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello Lambda"); } }; r.run(); / lambda / Runnable r1 = () -> System.out.println("Hello Lambda"); r1.run(); } }
-
格式二:有一个参数,并且无返回值。
(x) -> System.out.println(x);
比如:
public class TestLambd1 { @Test public void test() { Consumer<String> con = (x) -> System.out.println(x); con.accept("Hello Lambda"); } }
-
格式三:如果只有一个参数,那么小括号可以不写。
x -> System.out.println(x);
-
格式四:多个参数,有返回值,且 lambda 体中有多条语句。
public class TestLambd1 { @Test public void test() { Comparator<Integer> com = (x, y) -> { System.out.println("Hello Lambda"); return Integer.compare(x, y); }; } }
-
格式五:有返回值,若 lambda 体中只有一条语句,return 和 {} 可以省略。
public class TestLambd1 { @Test public void test() { Comparator<Integer> com = (x, y) -> Integer.compare(x, y); } }
-
格式六:lambda 表达式的参数列表可以省略不写,因为 JVM 编译器通过上下文可以推断数据类型。
1.3 JAVA8 内置的四大核心函数式接口
除了此四大核心函数式接口外还有类似的子接口,这里就不过多赘述。
1.3.1 消费型接口 Consumer<T>
void accept(T t);
public class TestLambd1 {
@Test
public void test() {
happy(100, (m) -> System.out.println("消费:" + x + "元"));
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
}
1.3.2 供给型接口Supplier<T>
T get();
public class TestLambd1 {
@Test
public void test() {
// 通过随机数产生
List<Integer> res = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : res) {
System.out.println(num);
}
}
// 需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
}
1.3.3 函数型接口Function<T, R>
R apply(T t);
public class TestLambd1 {
@Test
public void test() {
// 处理字符串的方法,去掉首位空格
String newStr = strHandler("\t\t\t haha", (str) -> str.trim());
System.out.println(newStr);
// 处理字符串的方法,数据截取
String subStr = strHandler("hahahaha", (str) -> str.substring(1,3));
System.out.println(subStr);
}
// 需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
}
1.3.4 断言型接口 Predicate<T>
boolean test(T t);
public class TestLambd1 {
@Test
public void test() {
List<String> list = Arrays.aslist("Hello", "Lambda", "www");
List<String> res = filterStr(list, (str) -> s.length > 3);
for (String s ; res) {
System.out.println(s);
}
}
// 需求:将满足条件的字符串放入集合
public List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> strList = new ArrayList<>();
for (String str:list) {
if(pre.test(pre)) {
strList.add(str);
}
}
return strList;
}
}
1.4 方法引用
如果 lambda 体中的内容已有方法实现了,我们可以使用方法引用。方法引用可以理解为 lambda 表达式的另外一种表现形式。
注意事项:
- lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。
- 如果 lambda 参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用
ClassName::MethodName
。
方法引用主要有以下三种格式:对象::实例方法名
;类::静态方法名
;类::实例方法名
。
对象::实例方法名
;
public class TestLambd1 {
@Test
public void test() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("abc");
// 进入 println 之后,其内容如下,println 为实例方法,属于PrintStream类
/*
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
*/
// 所以上面的 con 对应的代码行也可以写成
PrintStream ps = System.out;
Consumer<String> con1 = ps::println;
con1.accept("abc");
// 或者
Consumer<String> con2 = System.out::println;
con2.accept("abc");
}
}
类::静态方法名
;
public class TestLambd1 {
@Test
public void test() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
// 进入 Integer.compare 之后,其内容如下,compare 为静态方法,属于Integer类
/*
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
*/
// 或者
Comparator<Integer> com1 = Integer::compare;
}
}
类::实例方法名
。
public class TestLambd1 {
@Test
public void test() {
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String,<