Java8新特性----Lambda表达式详细探讨
Java8新特性
- Lambda表达式
- 入门演示
- 案例1
- 如何解决 cannot be cast to java.lang.Comparable问题?
- 案例2
- 优化方式一 : 策略设计模式
- 优化方式二: 策略设计模式+匿名内部实现接口,减少创建实体类的麻烦
- 优化方式三: lambda表达式
- 优化方式四: stream流
- Lambda语法
- 语法格式一 : 无参数,无返回值
- 注意: 局部内部类与局部变量
- 语法格式二: 有一个参数,无返回值
- 语法格式三: 如果一个参数,那么小括号可以不写
- 语法格式四:有两个参数,有返回值,lambda体中有多条语句
- 语法格式五:若lambda体中只有一条语句,那么return和{}都可以省略不写
- 语法格式六: lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
- Lambda需要函数式接口的支持
- 函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口,可以使用@FunctionalIterface修饰,检查当前接口是否式函数式接口
- 我们可以通过lambda来实现函数式接口里面的唯一的抽象方法
- 举例一
- 涉及知识点一: Interage.compareTo()
- 涉及知识点二: Collections工具类
- 内置四大核心函数式接口
- Consumer :消费型接口
- Supplier:供给型接口
- Function
Lambda表达式
Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升
入门演示
案例1
public class TestMain
{//使用匿名内部类完成比较@Testpublic void test(){//比较器 匿名内部类,创建该接口的一个实现类Comparator<People> com=new Comparator<People>() {@Overridepublic int compare(People o1, People o2) {return o1.getAge()-o2.getAge();}};//TreeSet的特点是可排序、不重复TreeSet<People> ts=new TreeSet<>(com);ts.add(new People("大忽悠",20));ts.add(new People("小忽悠",18));ts.add(new People("大大大",22));ts.add(new People("小朋友",17));ts.forEach(System.out::println);}//lambda表达式替代匿名内部类@Testpublic void test1(){//比较器Comparator<People> com=(p1,p2)-> p1.getAge()-p2.getAge();//TreeSet的特点是可排序、不重复TreeSet<People> ts=new TreeSet<>(com);ts.add(new People("大忽悠",20));ts.add(new People("小忽悠",18));ts.add(new People("大大大",22));ts.add(new People("小朋友",17));ts.forEach(System.out::println);}
}
如何解决 cannot be cast to java.lang.Comparable问题?
如何解决 cannot be cast to java.lang.Comparable问题?
案例2
要求对下面的代码进行优化:
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",21,4000),new People("3号",19,5000),new People("4号",20,3500));//获取年龄大于18的public List<People> getAgeOver18(){List<People> list=new ArrayList<>();for (People p:peopleList){if(p.getAge()>18)list.add(p);}return list;}//获取工资大于3000的public List<People> getMoneyOver3000(){List<People> list=new ArrayList<>();for (People p:peopleList){if(p.getMoney()>3000)list.add(p);}return list;}@Testpublic void test(){List<People> ageOver18 = getAgeOver18();ageOver18.forEach(System.out::println);System.out.println("======================================");List<People> moneyOver3000=getMoneyOver3000();moneyOver3000.forEach(System.out::println);}
}
优化方式一 : 策略设计模式
声明一个接口MyPrediect
public interface MyPrediect<T>
{public boolean test(T t);
}
接口的实现类一FilterPeoAge,负责过滤年龄:
public class FilterPeoAge implements MyPrediect<People>{@Overridepublic boolean test(People people) {return people.getAge()>18;}
}
接口实现类二FilterPeoMoney,负责过滤金钱
public class FilterPeoMoney implements MyPrediect<People>{@Overridepublic boolean test(People people) {return people.getMoney()>3000;}
}
测试演示:
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",21,4000),new People("3号",19,5000),new People("4号",20,3500));public List<People> FilterPeo(List<People> list,MyPrediect<People> mp){List<People> peopleList=new ArrayList<>();for (People p:list){if(mp.test(p))peopleList.add(p);}return peopleList;}@Testpublic void test(){List<People> peopleList = FilterPeo(this.peopleList, new FilterPeoAge());peopleList.forEach(System.out::println);System.out.println("===========================");List<People> peopleList1 = FilterPeo(peopleList, new FilterPeoMoney());peopleList1.forEach(System.out::println);}
}
当我们还需要安装某个策略进行过滤时,只需要实现接口,完成相应策略过滤逻辑编写即可
优化方式二: 策略设计模式+匿名内部实现接口,减少创建实体类的麻烦
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",21,4000),new People("3号",19,5000),new People("4号",20,3500));public List<People> FilterPeo(List<People> list,MyPrediect<People> mp){List<People> peopleList=new ArrayList<>();for (People p:list){if(mp.test(p))peopleList.add(p);}return peopleList;}@Testpublic void test(){List<People> peopleList = FilterPeo(this.peopleList, new MyPrediect<People>() {@Overridepublic boolean test(People people) {return people.getAge()>18;}});peopleList.forEach(System.out::println);System.out.println("===========================");List<People> peopleList1 = FilterPeo(peopleList, new MyPrediect<People>() {@Overridepublic boolean test(People people) {return people.getMoney()>3000;}});peopleList1.forEach(System.out::println);}
}
优化方式三: lambda表达式
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",21,4000),new People("3号",19,5000),new People("4号",20,3500));public List<People> FilterPeo(List<People> list,MyPrediect<People> mp){List<People> peopleList=new ArrayList<>();for (People p:list){if(mp.test(p))peopleList.add(p);}return peopleList;}@Testpublic void test(){List<People> peopleList = FilterPeo(this.peopleList, (people)-> people.getMoney()>4000);peopleList.forEach(System.out::println);}
}
优化方式四: stream流
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",21,4000),new People("3号",19,5000),new People("4号",20,3500));public List<People> FilterPeo(List<People> list,MyPrediect<People> mp){List<People> peopleList=new ArrayList<>();for (People p:list){if(mp.test(p))peopleList.add(p);}return peopleList;}@Testpublic void test(){peopleList.stream().filter(people -> people.getMoney()>3000).limit(2).forEach(System.out::println);}
}
Lambda语法
- 操作符:->
- 左侧:参数列表
- 右侧:执行代码块 / Lambda 体
即lambda是对接口的抽象方法的实现,可能有人会问,如果接口中抽象方法存在多个,那lambda是对哪个抽象方法的实现呢?
其实lambda需要一个函数式接口的支持,即当前接口只有一个抽象方法
语法格式一 : 无参数,无返回值
@Testpublic void test(){Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("方法执行中.....");}};runnable.run();System.out.println("----------------------");Runnable r1=()-> System.out.println("r1执行中....");r1.run();}
注意: 局部内部类与局部变量
局部内部类在JDK8之前只能使用成员变量和被final修饰的局部变量。JDK8之后,局部内部类如果使用局部变量那么局部变量默认被final修饰,但如果局部变量被重新赋值,那么局部内部类将不能在使用。具体看下例子:
public void show() {int j = 0; //jdk1.8后默认被final修饰。1.8之前局部内部类只能访问成员变量,和被final修饰的局部变量class A{public void showA() {System.out.println(i);System.out.println(j);}}
// j = 2;//如果对局部变量做了修改,则默认会变成不被final修饰。局部内部类不可调用}//注:有静态成员的一定是静态内部类
lambda这里跟匿名内部类用法一致
语法格式二: 有一个参数,无返回值
public class TestMain
{@Testpublic void test(){Consumer<String> consumer=(x)-> System.out.println(x);// void accept(T t); 对该抽象方法进行实现consumer.accept("大忽悠");}
}
语法格式三: 如果一个参数,那么小括号可以不写
Consumer<String> consumer=x-> System.out.println(x);// void accept(T t); 对该抽象方法进行实现consumer.accept("大忽悠");
语法格式四:有两个参数,有返回值,lambda体中有多条语句
public class TestMain
{@Testpublic void test(){// int compare(T o1, T o2);重写该方法Comparator<Integer> com=(x,y)->{System.out.println("函数式接口");return Integer.compare(x,y);};int compare = com.compare(1, 2);System.out.println(compare);}
}
语法格式五:若lambda体中只有一条语句,那么return和{}都可以省略不写
public void test(){// int compare(T o1, T o2);重写该方法Comparator<Integer> com=(x,y)->Integer.compare(x,y);int compare = com.compare(1, 2);System.out.println(compare);}
语法格式六: lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
Lambda需要函数式接口的支持
函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口,可以使用@FunctionalIterface修饰,检查当前接口是否式函数式接口
我们可以通过lambda来实现函数式接口里面的唯一的抽象方法
举例一
public class TestMain
{List<People> peopleList= Arrays.asList(new People("1号",18,3000),new People("2号",20,4000),new People("3号",18,5000),new People("4号",20,3500));//先安装年龄升序排序,年龄相同,再安装money降序排序@Testvoid test(){//重写下面这个方法,比较器可以为空// public static <T> void sort(List<T> list, Comparator<? super T> c) {// list.sort(c);// }Collections.sort(peopleList,(p1,p2)->{if(p1.getAge()==p2.getAge())return -p1.getMoney().compareTo(p2.getMoney());elsereturn p1.getAge().compareTo(p2.getAge());});peopleList.forEach(System.out::println);}
}
涉及知识点一: Interage.compareTo()
Integer obj2=100;//比较大小System.out.println(obj2.compareTo(100));System.out.println(obj2.compareTo(102));System.out.println(obj2.compareTo(10));
结果: 0 , -1 , 1 ,即大于返回 1 ,小于返回 -1 ,等于返回 0
涉及知识点二: Collections工具类
详细用法
内置四大核心函数式接口
Consumer<T> :消费型接口void accept(T t);Supplier<T>:供给型接口T get(T t);Function<T,R>:函数型接口R apply(T t);Predicate<T>:断言型接口boolean test(T t);
Consumer :消费型接口
@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t);
}
测试:
public class TestMain
{@Testvoid test(){//这里的lambda表达式实现了对应的抽象函数happy(10000,(m)-> System.out.println("我有: "+m));}public void happy(Integer money,Consumer<Integer> com){com.accept(money);}
}
Supplier:供给型接口
@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}
测试:
public class TestMain
{@Testvoid test(){List<String> numList=getNumList(5,()->UUID.randomUUID().toString().substring(0,8));numList.forEach(System.out::println);}//需求: 产生指定个数的随机id,并放入集合中public List<String> getNumList(int num, Supplier<String> supplier){ArrayList<String> integers = new ArrayList<String>();for(int i=0;i<num;i++){integers.add(supplier.get());}return integers;}
}
Function<T,R>: 函数型接口
public interface Function<T, R>{R apply(T t);}
测试:
public class TestMain
{@Testvoid test(){String str=StrHandler("\t\t\t 大忽悠 \t\t\t",(s)->s.trim());System.out.println(str);}//需求: 处理字符串public String StrHandler(String str, Function<String,String> f){return f.apply(str);//返回被处理过后的字符串}
}
涉及知识点: trim()函数
trim()方法的使用
Predicate:断言型接口
@FunctionalInterface
public interface Predicate<T> {/*** Evaluates this predicate on the given argument.** @param t the input argument* @return {@code true} if the input argument matches the predicate,* otherwise {@code false}*/boolean test(T t);}
测试:
public class TestMain
{@Testvoid test(){StrHandler("大忽悠啊",(str)->str.length()>3);StrHandler("嘿嘿",(str)->str.length()>3);}//需求: 处理字符串public void StrHandler(String str, Predicate<String> predicate){if(predicate.test(str))System.out.println(str);elseSystem.out.println("太短了");}
}
其他常用函数式接口
Java8新特性----Lambda表达式详细探讨相关推荐
- java8新特性lambda表达式、函数式编程、方法引用和接口默认方法以及内部类访问外部变量
一提到java是一种什么语言? 大多数人肯定异口同声的说是一门面向对象的语言,这种观点从我们开始学java就已经根深蒂固了,但是学到java8新特性函数式编程的时候,我才知道java并不是纯面向对象的 ...
- java8新特性-lambda表达式入门学习
定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expressi ...
- java8新特性lambda表达式概述
定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expres ...
- Java8新特性——lambda表达式
什么是lambda表达式? Lambda 表达式是Java 8 的新特性,是一种新的编程语法.lambda语义简洁明了,性能良好,是Java 8 的一大亮点.废话不多说,我们来看个例子. 从内部类到l ...
- java8新特性-lambda表达式和stream API的简单使用
一.为什么使用lambda Lambda 是一个 匿名函数,我们可以把 Lambda表达式理解为是 一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风 ...
- java compare 返回值_关于Java你不知道的那些事之Java8新特性[Lambda表达式和函数式接口]...
前言 为什么要用Lambda表达式? Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,将代码像数据一样传递,这样可以写出更简洁.更灵活的代码,作为一个更紧凑的代码风 ...
- 2020.10.20课堂笔记(java8新特性 lambda表达式)
一.什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个"值". 如果你想把"一块代码"赋给一个Java变量,应该怎么做呢? 比如,我想把右 ...
- Java8 新特性 -- Lambda表达式:函数式接口、方法的默认实现和静态方法、方法引用、注解、类型推测、Optional类、Stream类、调用JavaScript、Base64
文章目录 1. Lambda表达式 1.1 Lambda表达式语法 1.2 Lambda表达式示例 1.3 说明:函数式接口 2. 方法的默认实现和静态方法 3. 方法引用 3.1 方法引用示例 4. ...
- Java8 新特性lambda表达式(一)初始
本篇参考Richard Warburton的 java8 Lambdas :Functional Programming for the Masses 学习lambda表达式之前,需要知道什么是函数式 ...
最新文章
- thinkphp $this-display()报错
- Linux可以对目录进行硬链接,Linux硬链接与软链接原理及用法解析
- 《C和指针》——宏中容易出现的错误
- vue 不识别svg_vue配置svg 图标显示不出来
- python常用第三方库(转载)
- 怎么把打开方式还原计算机程序,打开方式怎么还原【图文】
- Linux有问必答:如何在树莓派上安装USB网络摄像头
- 常用容器管理器易受危险 exploit 攻击
- 了解PHP中$_SERVER变量对路径的解析
- java-线程同步问题
- Logit模型拟合实战案例(Biogeme)
- Windows和Linux平台上实现Word转PDF
- 智慧交通综合管理平台建设方案
- 华三Track+NQA+静态路由配置实例
- g7108 android5,三星G7108V移动4G版一键Root权限获取及USB驱动
- 系统设计系列之如何设计一个短链服务
- 深度学习大神都推荐入门必须读完这9篇论文
- 技术人“结构化思维”训练的一点想法和实践
- Android应用权限大全(Manifest.permission)
- 8051单片机Proteus仿真与开发实例-ULN2003A驱动步进电机仿真