Java8中引入了一个新的操作符“ -> ”,该操作符被称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两部分:
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需要执行的功能,即Lambda体
Lambda表达式常见的五种语法如下:
语法格式一:无参数,无返回值 (如Runable接口中的run方法)
@Test public void test01(){ Runnable run01 = new Runnable() { @Override public void run() { System.out.println("通过匿名内部函数实现!"); } }; run01.run(); Runnable run02 =() -> System.out.println("Hello Lambda!"); run02.run(); }2. 语法格式二:有一个参数,无返回值 (如Java8中的Consumer接口)
@Test public void test02(){ Consumer con01 = (x) -> System.out.println(x); //若只有一个参数,小括号可以省略不写 Consumer con02 =x -> System.out.println(x); //调用抽象方法 con01.accept("使用Lambda表达式,实现抽象方法,输出参数的值"); con02.accept("若只有一个参数,小括号可以省略不写"); }3. 语法格式三:有两个以上参数,有返回值,并且Lambda体中有多条语句,大括号必须写
@Test public void test03(){ Comparator<Integer> com = (x, y) -> { System.out.println("函数式接口"); return Integer.compare(x,y); }; int compare = com.compare(3, 6); System.out.println(compare);//输出结果为:函数式接口 -1 }4. 语法格式四:若Lambda体中只有一条语句,return 和 大括号 都可以省略不写
@Test public void test04(){ Comparator<Integer> com = (x, y) -> Integer.compare(x,y); int compare = com.compare(3, 6); System.out.println(compare); // 输出结果为: -1 }5. 语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
@Test public void test05(){ Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x,y); int compare = com.compare(3, 6); System.out.println(compare); // 输出结果为: -1 }Lambad表达式需要“函数式接口“的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口,可以使用注解@FunctionalInterface修饰,检查是否是函数式接口
注意:在jdk1.8之前,在局部内部类中,使用了同级别的局部变量,该局部变量必须使用final修饰,JDK1.8之后,该局部变量被默认使用了final修饰,仍然不允许被修改,不需要我们手动去加了
消费型接口
@FunctionalInterface public interface Consumer<T> { //一个参数,无返回值 void accept(T t); }供给型接口
@FunctionalInterface public interface Supplier<T> { //无参数,有返回值 T get(); }函数性接口
@FunctionalInterface public interface Function<T, R> { // T代表参数,R代表返回值 R apply(T t); }断言型接口(用作一些判断操作)
@FunctionalInterface public interface Predicate<T> { //一个参数,返回值为boolean类型,常用来做一些判断操作 boolean test(T t); }下面对Java8提供四大核心函数式接口,进行简单的测试运用:
消费型接口测试
@Test public void test06(){ //使用Lambda表达式,对Consumer接口中的accept()进行了具体实现 happy(10000.00,(money) -> System.out.println("今天用了10000元买了台Mac笔记本电脑")); } /** * 自定义方法调用Consumer接口的抽象方法 * @param money * @param consumer */ public void happy(Double money,Consumer<Double> consumer){ consumer.accept(money); }供给型接口测试
@Test public void test07(){ //获取10个100以内的随机数 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; }函数型接口测试
//函数型接口:可以对参数进行一些操作,然后返回操作结果 @Test public void test08(){ //由于Lambad体中只有一条语句,这里return 和 大括号 都省略了 String newStr = strHandler("函数型接口测试",(str) -> str.substring(3,str.length())); System.out.println(newStr);// 输出结果为: 接口测试 } //需求:用于处理字符串 public String strHandler(String str,Function<String,String> fun){ return fun.apply(str); }断言型接口
@Test public void test09(){ List<String> list = Arrays.asList("hello","Lambda","easy","OK"); //获取字符串长度大于4的集合 List<String> strList = filterStr(list,(s) -> {return s.length()>4;}); System.out.println(strList); // 输出结果为:[hello, Lambda] } //将满足条件的字符串,放入集合中 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; } 方法引用若Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为Lambda表达式的另一种表现形式)。
主要有三种语法格式:
语法格式一: 对象::实例方法名
语法格式二: 类名::静态方法名