lambda表达式:
可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称。
函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
传递——Lambda表达式可以作为参数传递给方法或存储在变量中。(行为参数)
简洁——无需像匿名类那样写很多模板代码。
总结:快速实现接口中的方法
1:基本语法
使用lambda表达式实现配合Collections完成排序功能。
对比,匿名内部类
感受:lambda是快速实现接口中的方法
自定义接口:里面只有一个抽象方法
自定义测试类: 里面的某一个方法 参数为 接口类型
main : 进行测试。
2:lambda表达式用法:
1,没有参数,没有返回值
()->{}
注:如果大括号里只有一句代码 ()->代码 该代码不要;号结尾
2,没有参数,有返回值
()->{return 值;}
注:如果大括号里只有一句代码 ()->返回值 该代码不要;号结尾
3,有一个参数,没有返回值
(a)->{System.out.println(a)}
注:如果大括号里只有一句代码 (a)->代码 该代码不要;号结尾
4,有一个参数,有返回值
(a)->{a++;return a;}
注:如果大括号里只有一句代码 (a)->返回值 该代码不要;号结尾
注:如果只有一个参数,()也可以不写。
a->{};
5,有两个参数,没有返回值
(a,b)->{a++;System.out.println(b);}
注:如果大括号里只有一句代码 (a,b)->代码 该代码不要;号结尾
6,有两个参数,有返回值
(a,b)->{a++;return a;}
注:如果大括号里只有一句代码 (a,b)->返回值 该代码不要;号结尾
注:大括号里的代码需要打分号。就是普通正常代码。
注:参数里面是不用谢参数类型的。
3:lambda中变量的问题:
lambda中可以使用成员变量,局部变量,但是使用过局部变量以后,该局部变量就必须为final,所以不能再修改了。
4:在函数式接口上使用lambda表达式
jdk8中新引入了几个函数式接口:
- 【boolean放回值,一个泛型参数】Predicate接口 test(T t)
接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。 boolean test(T
t);表示:t进行断言,返回true或者false,可以配合其他的方法使用,如filter();
Predicate接口是用来支持java函数式编程新增的一个接口,使用这个接口和lambda表达式就可以以更少的代码为API方法添加更多的动态行为。
还有两个默认方法 and or
/*
@FunctionalInterface
interface Predicate<T>{
boolean test(T t);
}
*/
接口应用:
public class LambdaTest4 {
public static void filter(List<String> languages, Predicate<String> condition) {
for(String name: languages) {
if(condition.test(name)) {
System.out.println(name + " ");
}
}
}
public static void main(String[] args) {
List<String> languages = Arrays.asList("Java", "html5","JavaScript", "C++", "hibernate", "PHP");
//开头是J的语言
filter(languages,(String name)->name.startsWith("J"));
//5结尾的
filter(languages,(String name)->name.endsWith("5"));
//所有的语言
filter(languages,(name)->true);
//一个都不显示
filter(languages,(name)->false);
//显示名字长度大于4
filter(languages,(name)->name.length()>4);
System.out.println("-----------------------");
//名字以J开头并且长度大于4的
Predicate<String> c1 = (name)->name.startsWith("J");
Predicate<String> c2 = (name)->name.length()>4;
filter(languages,c1.and(c2));
//名字不是以J开头
Predicate<String> c3 = (name)->name.startsWith("J");
filter(languages,c3.negate());
//名字以J开头或者长度小于4的
Predicate<String> c4 = (name)->name.startsWith("J");
Predicate<String> c5 = (name)->name.length()<4;
filter(languages,c4.or(c5));
//名字为Java的
filter(languages,Predicate.isEqual("Java"));
//判断俩个字符串是否相等
boolean test = Predicate.isEqual("hello").test("world");
System.out.println(test);
}
源代码解析:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
-
【一个放回值,一个参数】Function<T, R> 接口 R apply(T t); 有参数有返回值
参数 返回值
接收T对象,返回R对象
表示接受一个参数并产生结果的函数。/*@FunctionalInterface interface Function<T, R>{ R apply(T t); }*/ 接口应用: public class LambdaTest6 { public static <T, R> List<R> map(List<T> list,Function<T, R> f) { List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } public static void main(String[] args) { List<Integer> list = map( Arrays.asList("lambdas","in","action"), (String s) -> s.length() ); System.out.println(list);// [7, 2, 6] } }
-
【一个返回值,没有参数】Supplier接口 T get(); 没参数有返回值
返回值
代表结果供应商。
没有要求每次调用供应商时都会返回新的或不同的结果。/*@FunctionalInterface interface Supplier<T>{ T get(); }*/ 接口应用: public class LambdaTest7 { public static void main(String[] args) { //生成一个八位的随机字符串 Supplier<String> f = ()->{ String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 8; i++) { //生成[0,base.length)之间的随机数 int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); }; System.out.println(f.get()); } }
-
【没有返回,一个参数】Consumer 接口 void accept(T t); 有参数没返回值
参数 对给定的参数执行此操作
这个接口,接收一个泛型的参数T,然后调用accept,对这个参数做一系列的操作,没有返回值;接口应用: public class LambdaTest5 { public static <T> void forEach(List<T> list, Consumer<T> c){ for(T i: list){ c.accept(i); } } public static void main(String[] args) { forEach( Arrays.asList(1,2,3,4,5), (Integer i) -> System.out.println(i) ); } } 另外需要注意的接口: 其用法和上面介绍的接口使用方式类同
-
【一个返回值,两个参数】BiFunction<T, U, R>接口
R apply(T t, U u)
将一个T和一个U输入,
返回一个R作为输出 -
【一个返回值,两个参数】BinaryOperator接口
T apply(T t, T t)
将两个T作为输入,
返回一个T作为输出
BinaryOperator接口继承了BiFunction接口 -
【没有返回值,两个参数】BiConsumer<T, U>接口
void accept(T t, U u)
将俩个参数传入,
没有返回值5,java常用的函数式编程接口使用:
1. 比较器
2. 实现线程
3. 绑定事件
4. 集合数据排序
类型推断:
你还可以进一步简化你的代码。
Java编译器会从上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式,这意味着它也可以推断出适合Lambda的签名,
因为函数描述符可以通过目标类型来得到。这样做的好处在于,编译器可以了解Lambda表达式的参数类型,这样就可以在Lambda语法
中省去标注参数类型。 List list = new ArrayList<>();
lambda表达式:
方法引用:简化lambda,重复利用已有的代码
方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。
方法引用可以被看作仅仅调用 【特定方法的Lambda】 的一种快捷写法。
当你需要使用方法引用时,目标引用放在分隔符::前,方法的名称放在后面。
1,引用构造器
Supplier<类名> 变量名 = 类名::new
Student stu = 变量名.get();
2,引用有参数构造器
BiFunction<参数1, 参数2, 类名> bf = 类名::new;
类名 变量名 = bf.apply(值1,值2);
3,引用数组构造器
IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10);
4,引用静态方法
函数接口类型 变量名 = 类名::静态方法名
5,普通方法的引用:
函数接口类型 变量名 = 对象::方法名;
6,实例方法引用
类名::方法名A;
将lambda的参数 直接当做 A方法的参数
这种写法,不讨论返回值的问题。有就自动返回。
1,如果lambda的参数正好和::后面方法A的参数一样,那么就是调用::后面的方法A,把lambda的参数传进去
// R apply(T t);
Consumer<String> f = System.out::println;
Consumer<String> f1 = (t)->{System.out.println(t);};
// void accept(T t, U u);
BiConsumer<Integer,Integer> bc = (a,b)->{Math.max(a, b);};
BiConsumer<Integer,Integer> bc1 = Math::max;
2,如果lambda的参数 比::后面方法A的参数多,那么就是第一个参数调用::后面方法A,把lambda剩下的参数传入::后面的方法A
// R apply(T t);
Function<String,String> fun1 = String::toUpperCase;
Function<String,String> fun = (t)->t.toUpperCase();
// void accept(T t, U u);
BiConsumer<String,Integer> bc = String::substring;
BiConsumer<String,Integer> bc1 = (a,b)->{a.substring(b);};