Lambda表达式
Lambda表达式是一个匿名函数,匿名内部对象,根据面向对象的特征了解到,接口是不可以被实例化的,但是可以通过其继承该接口的子类来创建父类对象,即该接口对象,由于接口是全抽象的,所以子类对于父类的方法必须重写,在这里Lambda表达式应用就使用了此原理,使之得到接口对象;
public class Test01 {
public static void main(String[] args) {
//在这里new A(){}实际上创建接口A的子类对象,由于会自动向上转型,所以得到了父类对象,即A的对象a
A a=new A(){
//重写sum方法
@Override
public int sum(int a, int b) {
int sum=a+b;
System.out.println("两数之和为:"+sum);
return sum;
}
//重写pow1方法
@Override
public double pow1(int a,int b){
double p=Math.pow(a,b);
System.out.println(p);
return p;
}
};
a.sum(1,2);
a.pow1(1,3);
}
}
interface A{
int sum(int a,int b); //定义一个求和的方法
double pow1(int a,int b); //定义一个求a^b的方法
}
Lambda表达式的使用条件:
- Lambda表达式的使用需要函数式接口的支持。
函数式接口:接口种有且仅有一个抽象方法的接口,称为函数式接口。
Lambda的使用用例二--------无参数,无返回值情况
package com.ysh.demo.review03;
/**
* 需求:利用Lambda表达式打印Helloword,并且传入一个String类型的参数
*/
public class DemoLambdaTest01 {
public static void main(String[] args) {
/**
* 方法一
*/
RandomTest rt=new RandomTest() {
//重写rdt方法
@Override
public void rdt() {
System.out.println("HelloWorld ");
}
};
rt.rdt(); //调用重写后的方法,在这里发生了多态现象
/**
* 方法二
* Lambda写法思路:{}可以省略
*/
RandomTest rt2=()->{
System.out.println("HelloWorld ");
};
rt2.rdt();
}
}
interface RandomTest{
void rdt();
}
Lambda的使用用例一-------有参数,无返回值情况
package com.ysh.demo.review03;
/**
* 需求:利用Lambda表达式打印Helloword,并且传入一个String类型的参数追加到HelloWord末尾
*/
public class DemoLambdaTest01 {
public static void main(String[] args) {
/**
* 方法一
*/
RandomTest rt=new RandomTest() {
//重写rdt方法
@Override
public void rdt(String s) {
System.out.println("HelloWorld "+s);
}
};
rt.rdt("yang"); //调用重写后的方法,在这里发生了多态现象
/**
* 方法二
* Lambda写法思路:(String s) 表接口中方法签名其中的String可以省略
*/
RandomTest rt2=(String s)->{
System.out.println("HelloWorld "+ s);
};
rt2.rdt("yang");
}
}
interface RandomTest{
void rdt(String s);
}
Lambda使用用例三----有参数有返回值情况
package com.ysh.demo.review03;
/**
* 需求:利用Lambda表达式打印Helloword,并且传入一个String类型的参数追加到HelloWord末尾
*/
public class DemoLambdaTest01 {
public static void main(String[] args) {
/**
* 方法一
*/
RandomTest rt=new RandomTest() {
//重写rdt方法
@Override
public int rdt(String s) {
System.out.println("HelloWorld "+s);
return 1;
}
};
rt.rdt("yang"); //调用重写后的方法,在这里发生了多态现象
/**
* 方法二
*
*/
RandomTest rt2=(String s)->{
System.out.println("HelloWorld "+ s);
return 1;
};
rt2.rdt("yang");
}
}
interface RandomTest{
int rdt(String s);
}
Lambda使用用例四------有返回值无参数情况
package com.ysh.demo.review03;
/**
* 需求:利用Lambda表达式打印Helloword,并且传入一个String类型的参数
*/
public class DemoLambdaTest01 {
public static void main(String[] args) {
/**
* 方法一
*/
RandomTest rt=new RandomTest() {
//重写rdt方法
@Override
public String rdt() {
return "Helloworld";
}
};
rt.rdt(); //调用重写后的方法,在这里发生了多态现象
/**
* 方法二
*
*/
RandomTest rt2=()->{
return "HelloWorld";
};
//以下调用效果跟上面调用效果一样
RandomTest rt3=()-> "HelloWorld";
rt2.rdt();
}
}
interface RandomTest{
String rdt();
}
四大内置接口:消费型接口(Comsumer)、供给型接口(Supplier)、函数型接口(Function<T,R>)、断定性接口(Predictae)
消费型接口的基本使用(底层有个accept(T t)方法):
package com.ysh.demo.review03;
import java.util.Arrays;
import java.util.Collection;
public class DemoLambdaTes02 {
public static void main(String[] args) {
Collection<String> list= Arrays.asList("aaaa","bbbb","cccc","dddd");
//由于forEach(Consumer<? super T> action)中的参数类型是Consumer类型,但是Consumer是个接口,所有要得到父类对象必须通过实例化子类对象,即有个类继承与Consumer
list.forEach(s-> System.out.println(s));//s-> System.out.println(s)这个意思就是相当于与创建了一个继承Consumer接口的子类对象,但是通过自动向上继承,可以实例化父类接口对象
}
}
供给型接口的基本使用(底层有个T get()方法):
package com.ysh.demo.review03;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.function.Supplier;
/**
* 需求:产生指定个数的整数,整数范围为并放入集合中
*/
public class DemoLambdaTest02 {
public static void main(String[] args) {
//()->(int)(Math.random()*100+1)表示重写底层方法T get()
List<Integer> numList=getNumList(10,()->(int)(Math.random()*100+1));
}
//实际上以上写法相当于以下写法
List<Integer> numList02=getNumList(10,()->{
int a=(int)(Math.random()*100+1);
return a;
});
public static 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;
}
}
Function<T, R>函数型接口的基本使用(底层有个R apply(T t)方法):
package com.ysh.demo.review03;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 需求:1、去掉字符串两端的空格
* 2、截取字符串
*/
public class DemoLambdaTest03 {
public static void main(String[] args) {
//(str) -> {return str.trim();}表示重写R apply(T t)方法
String newStr = strHandler(" shsxt ", (str) -> {return str.trim();});
System.out.println(newStr);
newStr = strHandler("shsxt", (str) -> str.substring(2, 5));
System.out.println(newStr);
}
public static String strHandler(String str, Function<String, String> fun) { return fun.apply(str); }
}
Predicate断言型接口(底层中有个Test(T)方法):
package com.ysh.demo.review03;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 需求:将满足条件的字符串,放入集合中,并且返回一个集合
*/
public class DemoLambdaTest02 {
public static void main(String[] args) {
List<String> list3=Arrays.asList("aa","bbbb","cccc","dddd");
//重写Predicate接口中的test方法
filterStr(list3,(s)->{
boolean b=(s.length()>3);
return b;
});
filterStr(list3,(s)->(s.length()>3)); //等价于以上写法,即return和{}可以省略不写
}
public static List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> list1 = new ArrayList<>();
for (String str1 : list) { //遍历集合
if (pre.test(str1)) { //筛选元素,Predicate接口中有个test方法,即重写Predicate中的test方法即可设定筛选条件
list1.add(str1); //将符合要求的元素添加到集合中
}
}
return list1;
}
}
方法引用的4中表现形式:
- 对象::方法名
- 类名::静态方法名
- 类名::普通方法名
- 类名::new(构造器引用)
对象::方法名:
public static void test2(){
Student stu=new Student("yang",18,1.34);
/*
方法一
*/
Supplier<String> supplier=()->stu.getName();
System.out.println(supplier.get());
/*
方法二
*/
/*由于getName()方法在Student中已经存在,所以在这里可以Lambda表达式中的
方法引用方式间接对Supplier中的get()方法实现重写过程,即构建Supplier类的匿名子类
*/
Supplier<String> supplier2=stu::getName;
System.out.println(supplier2.get());
}
类名::静态方法名:
/**
*运用方法:Lambda表达形式中的:类::静态方法名
*/
public static void test3(){
Comparator<Integer> cp=(t1,t2)->Integer.compare(t1,t2);
Comparator<Integer> cp2=Integer::compare;
}
类名::普通方法名:
/**
* 运用方法:Lambda表达形式中的:类:普通方法名
*/
public static void test4(){
BiPredicate<String,String> bp=(x,y)->x.equals(y);
BiPredicate<String,String> bp2=String::equals;
}
类名::new(构造器引用):
public static void test5(){
//Student stu2=new Student("yang",19,1.78);
Supplier<Student> supplier=Student::new;
System.out.println(supplier.get());
Supplier<Student> supplier1=()->new Student("yang",19,1.78);
System.out.println(supplier1.get());
//这种调用方式只能是传入实参与Student中的属性互相对应,没有什么操作空间,只能通过不断修改传入的实参值来改变属性值
BiFunction<String,Integer,Student> bf=Student::new;
//两者等价
BiFunction<String,Integer,Student> bf2=(s,b)->new Student(s,b);
//这种方式可以在new Student(s,b)对其形参形态进行变化,例如:new Student(s+"hello",b+1),具有很强的操作空间
System.out.println(bf2.apply("hello", 19));
System.out.println(bf.apply("sheng", 19));
}