Lembda表达式
Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
基本语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ ->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
左侧: 指定了 Lambda 表达式需要的所有参数
右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能。
/*
* 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
* 箭头操作符将 Lambda 表达式拆分成两部分:
*
* 左侧:Lambda 表达式的参数列表
* 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
*
* 语法格式一:无参数,无返回值
* () -> System.out.println("Hello Lambda!");
*
* 语法格式二:有一个参数,并且无返回值
* (x) -> System.out.println(x)
*
* 语法格式三:若只有一个参数,小括号可以省略不写
* x -> System.out.println(x)
*
* 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
* Comparator<Integer> com = (x, y) -> {
* System.out.println("函数式接口");
* return Integer.compare(x, y);
* };
*
* 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
* Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
*
* 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
* (Integer x, Integer y) -> Integer.compare(x, y);
*
* 上联:左右遇一括号省
* 下联:左侧推断类型省
* 横批:能省则省
*
* 二、Lambda 表达式需要“函数式接口”的支持
* 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
* 可以检查是否是函数式接口
*/
public class TestLambda2 {
@Test
public void test1(){
int num = 0;//jdk 1.7 前,必须是 final,而jdk1.8会自动将内部类中的变量声明为final类型。
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" + num);//此处如果改为num++依旧是不可行的,因为jdk1.8只是将其隐式声明final类型而已。
}
};
r.run();
System.out.println("-------------------------------");
Runnable r1 = () -> System.out.println("Hello Lambda!");
r1.run();
}
@Test
public void test2(){
Consumer<String> con = x -> System.out.println(x);
con.accept("我大尚硅谷威武!");
}
@Test
public void test3(){
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
@Test
public void test4(){
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
//对于语法格式6中JVM类型推断的的内容,我们可以这样理解。
@Test
public void test5(){
String[] strs = {"aaa", "bbb", "ccc"};//这样是可行的,因为JVM会做类型推断。
// String[] strs;
// strs = {"aaa", "bbb", "ccc"}; 这样是不可行的,因为JVM虚拟机做不了类型推断
List<String> list = new ArrayList<>();
show(new HashMap<>());
}
public void show(Map<String, Integer> map){
}
上述 Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”.
函数式接口
只包含一个抽象方法的接口,称为函数式接口。但我们通常并不自己去写一个函数式接口供自己使用,java已经提供了内置的四大核心函数式接口。
/*
* Java8 内置的四大核心函数式接口
*
* Consumer<T> : 消费型接口
* void accept(T t);
*
* Supplier<T> : 供给型接口
* T get();
*
* Function<T, R> : 函数型接口
* R apply(T t);
*
* Predicate<T> : 断言型接口
* boolean test(T t);
*
*/
public class TestLambda3 {
//Predicate<T> 断言型接口:
@Test
public void test4(){
List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}
//Function<T, R> 函数型接口:
@Test
public void test3(){
String newStr = strHandler("\t\t\t 我大尚硅谷威武 ", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("我大尚硅谷威武", (str) -> str.substring(2, 5));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
//Supplier<T> 供给型接口 :
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : numList) {
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;
}
//Consumer<T> 消费型接口 :
@Test
public void test1(){
happy(10000, (m) -> System.out.println("你们刚哥喜欢大宝剑,每次消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
}
这四大接口还有他们的子接口
方法引用与构造器引用
方法引用
我们先来看一下什么是方法引用:方法引用其实是Lambda表达式的另一种写法,
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用.
注意:实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:
- 对象::实例方法
- 类::静态方法
- 类::实例方法
public static void main(String[] args) {
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("哈哈");
Consumer<String> consumer2=x-> System.out.println(x);
consumer2.accept("呵呵");
//再次对Lambda表达式简写
//这种简写叫做方法引用
//你对接口中的抽象方法的实现逻辑中调用的这个方法,跟接口中的这个方法的返回值和形参列表一致的化,就可以用方法引用再次简写
Consumer<String> consumer3=System.out::println;
consumer3.accept("哈哈哈哈哈");
System.out.println("--------------------------------");
Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {//一个参数,一个返回值
int i = Integer.parseInt(s);//一个参数,一个返回值
return i;
}
};
Function<String, Integer> function2 =(x)->Integer.parseInt(x);
Function<String, Integer> function3=Integer::parseInt;
System.out.println("-------------------------");
BiFunction<Double, Double, Double> biFunction = new BiFunction<Double, Double, Double>() {
@Override
public Double apply(Double aDouble, Double aDouble2) {
Math.max(aDouble, aDouble2);
return null;
}
};
BiFunction<Double, Double, Double> biFunction2=(a,b)->Math.max(a,b);
//方法引用
BiFunction<Double, Double, Double> biFunction3=Math::max;
System.out.println("--------------------------");
Function<Integer, String> function1 = new Function<Integer, String>() {
@Override
public String apply(Integer s) {
String s1 = String.valueOf(s);
return s1;
}
};
Function<Integer, String> function4=String::valueOf;
}
构造器引用
格式:ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
//构造引用
Supplier<MyClass> supplier = new Supplier<MyClass>() {
@Override
public MyClass get() {
return new MyClass();
}
};
Supplier<MyClass> supplier2 = () -> new MyClass();
//构造引用
Supplier<MyClass> supplier3 = MyClass::new;
Function<String, MyClass> function = new Function<String, MyClass>() {
@Override
public MyClass apply(String s) {
return new MyClass(s);
}
};
MyClass zhangsan = function.apply("zhangsan");
Function<String, MyClass> function2 =(s)->new MyClass(s);
Function<String, MyClass> function3 =MyClass::new;