1. lambda
1. 什么是Lambda表达式
Lambda是一个匿名函数,即没有函数名的函数(简化了匿名委托的使用,让你让代码更加简洁)
2. Lambda表达式实例
//匿名内部类
Runnable r = new Runnable() {
@Override
public void run() {
System.out.print("hello toroot");
}
};
//lambda
Runnable r2 = ()->System.out.print("hello toroot");
//匿名内部类
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Long.compare(o1.length(),o2.length());
}
});
//lambda
TreeSet<String> ts2 = new TreeSet<>((o1,o2)-> Long.compare(o1.length(),o2.length()));
3. Lambda 表达式语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。
它将 Lambda 分为两个部分:
a. 左侧:指定了 Lambda 表达式需要的所有参数
b. 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
4. Lambda 表达式语法格式
1. 无参数,无返回值
public void test1() {
//一、语法格式一:无参数,无返回值
Runnable runnable =() -> System.out.println("Hello Lambda!");
}
2. 有一个参数,并且无返回值
public void test2() {
//语法格式二:有一个参数,并且无返回值
Consumer consumer = (x) -> System.out.println(x);
}
3. 若只有一个参数,小括号可以省略不写
public void test3() {
//语法格式三:若只有一个参数,小括号可以省略不写
Consumer consumer = x-> System.out.println(x);
}
4. 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
public void test4() {
//语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
5. 若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
public void test5() {
//语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
6. Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
public void test6() {
//语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
Comparator<Integer> com2 = (Integer x, Integer y) -> Integer.compare(x, y);
}
4. 函数式接口 ( @FunctionalInterfac )
Lambda
表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface
修饰可以检查是否是函数式接口
@FunctionalInterface
标记在接口上,“函数式接口“是指仅仅只包含一个抽象方法的接口,加上注释,写两个方法,IDE会报错。
@FunctionalInterface
public interface MyFun<T> {
public T getValue(T t);
}
public static void main(String[] args) {
String newStr = toUpperString((str)->str.toUpperCase(),"toroot");
System.out.println(newStr);
}
public static String toUpperString(MyFun<String> mf,String str) {
return mf.getValue(str);
}
5. Java内置函数式接口
全部的函数式接口可以查看 Java 8 函数式接口 这边抽取几个进行讲解
接口 | 参数 | 返回类型 | 示例 |
---|---|---|---|
Predicate | T | boolean | 这是个美女吗? |
Consumer | T | void | 输出一个值 |
Function<T,R> | T | R | 获得 Person对象的名字 |
Supplier | None | T | 工厂方法 |
UnaryOperator | T | T | 逻辑非 (!) |
BinaryOperator | (T, T) | T | 求两个数的乘积 (*) |
1.Predicate<T>
Predicate<T>
接受一个输入参数,返回一个布尔值结果。
/**
* 断言型接口:Predicate<T>
*/
public void test1 () {
List<Integer> l = new ArrayList<>();
l.add(102);
l.add(172);
l.add(13);
l.add(82);
l.add(109);
List<Integer> list = filterInt(l, x -> (x > 100));
for (Integer integer : list) {
System.out.println(integer);
}
}
/**
* 过滤集合
* @param list
* @param pre
* @return
*/
public List<Integer> filterInt(List<Integer> list, Predicate<Integer> pre){
List<Integer> l = new ArrayList<>();
for (Integer integer : list) {
if (pre.test(integer))
l.add(integer);
}
return l;
}
102
172
109
2. Consumer<T>
Consumer<T>
代表了接受一个输入参数并且无返回的操作
/**
* 消费型接口Consumer<T>
*/
public void test2 () {
consumo(500, (x) -> System.out.println(x));
}
public void consumo (double money, Consumer<Double> c) {
c.accept(money);
}
500.0
3. Function<T, R>
Function<T,R>
接受一个输入参数,返回一个结果。
/**
* 函数型接口:Function<R, T>
*/
public void test3 () {
String s = strOperar(" asdf ", x -> x.substring(0, 2));
System.out.println(s);
String s1 = strOperar(" asdf ", x -> x.trim());
System.out.println(s1);
}
/**
* 字符串操作
* @param str 需要处理得字符串
* @param fun Function接口
* @return 处理之后得字符传
*/
public String strOperar(String str, Function<String, String> fun) {
return fun.apply(str);
}
a
asdf
4. Supplier<T>
Supplier<T>
无参数,返回一个结果。
/**
* 供给型接口,Supplier<T>
*/
public void test4() {
Random ran = new Random();
List<Integer> list = supplier(10, () -> ran.nextInt(10));
for (Integer i : list) {
System.out.println(i);
}
}
/**
* 随机产生sum个数量得集合
* @param sum 集合内元素个数
* @param sup
* @return
*/
public List<Integer> supplier(int sum, Supplier<Integer> sup){
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < sum; i++) {
list.add(sup.get());
}
return list;
}
5
1
2
0
8
6
1
1
4
8
5. UnaryOperator<T>
UnaryOperator<T>
接受一个参数为类型T,返回值类型也为T。
/**
* UnaryOperator<T>
*/
public void test5() {
String endStr = unaryOperator("hello", (t) -> t+" zeking");
System.out.println(endStr);
}
/**
* 转大写 操作
* @param str
* @param u
* @return
*/
public String unaryOperator(String str, UnaryOperator<String> u) {
return u.apply(str.toUpperCase());
}
HELLO zeking
6. BinaryOperator<T,T>
BinaryOperator<T,T>
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
/**
* BinaryOperator<T>
*/
public void test6(){
int result = binaryOperator(5,6,(x,y)->{
return x*y;
});
System.out.println(result+"");
}
public int binaryOperator(int x ,int y,BinaryOperator<Integer> b){
return b.apply(x+1,y+2);
}
48
6. 方法引用( :: )
1. 介绍
- 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!) 方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。 如下三种主要使用情况 :
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
2. 什么时候可以用 ::方法引用(重点)
在我们使用Lambda表达式的时候,”->”右边部分是要执行的代码,即要完成的功能,可以把这部分称作Lambda体。有时候,当我们想要实现一个函数式接口的那个抽象方法,但是已经有类实现了我们想要的功能,这个时候我们就可以用方法引用来直接使用现有类的功能去实现
3. 示例
Person.java
public class Person {
private String name;
private Integer age;
private Integer score;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, Integer age, Integer score) {
this.name = name;
this.age = age;
this.score = score;
}
...... // 省略 get set 方法
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
public static void main(String... args) {
Person p1 = new Person("Zeking", 18, 60);
Person p2 = new Person("David", 38, 1);
Person p3 = new Person("Lucky", 28, 99);
List<Person> personList = new ArrayList<>();
personList.add(p1);
personList.add(p2);
personList.add(p3);
//这里我们需要比较list里面的person,按照年龄排序
//那么我们最常见的做法是
//sort(List<T> list, Comparator<? super T> c)
//1. 因为我们的sort方法的第二个参数是一个接口,所以我们需要实现一个匿名内部类
Collections.sort(personList, new Comparator<Person>() {
@Override
public int compare(Person person1, Person person2) {
return person1.getAge().compareTo(person2.getAge());
}
});
//2. 因为第二个参数是一个@FunctionalInterface的函数式接口,所以我们可以用lambda写法
Collections.sort(personList, (person1,person2) -> p1.getScore().compareTo(p2.getAge()));
//3. 因为第二个参数我们可以用lambda的方式去实现,
// 但是刚好又有代码(Comparator.comparing)已经实现了这个功能
// 这个时候我们就可以采用方法引用了
/**
* 重点:
* 当我们想要实现一个函数式接口的那个抽象方法,但是已经有类实现了我们想要的功能,
* 这个时候我们就可以用方法引用来直接使用现有类的功能去实现。
*/
Collections.sort(personList, Comparator.comparing(Person::getAge));
System.out.println(personList);
}
[Person{name='Zeking', age=18, score=60}, Person{name='Lucky', age=28, score=99}, Person{name='David', age=38, score=1}]
4. 对象 :: 实例方法
直接调用任意对象的实例方法,如 obj::equals 代表调用 obj 的 equals 方法与接口方法参数比较是否相等,效果等同 obj.equals(t);。
当前类的方法可用this::method进行调用,父类方法同理。
Person p1 = new Person("Zeking", 18, 60);
Person p2 = new Person("David", 38, 1);
Predicate<Person> p = p1::equals;
System.out.println(p.test(p2)); // false
5. 类 :: 静态方法
直接调用某类的静态方法,并将接口方法参数传入,
如Android中 TextUtils::isEmpty,效果等同 TextUtils.isEmpty(s);
TextUtils.isEmpty("ss");
Predicate<CharSequence> p = TextUtils::isEmpty;
boolean s = p.test("");
System.out.println(s); // true
BinaryOperator<Double> bo = (n1,n2) ->Math.pow(n1,n2);
BinaryOperator<Double> bo2 = Math::pow;
System.out.println(bo2.apply(3.0,2.0)); // 9.0
public static void main(String[] args) {
Consumer<String> c = x->System.out.println(x);
//等同于
Consumer<String> c2 = System.out::print;
c2.accept("hello zeking"); // hello zeking
}
6. 类 :: 实例方法
较为特殊,将接口方法参数列表的第一个参数作为方法调用者,其余参数作为方法参数。由于此类接口较少,故选择 Java 提供的 BiFunction 接口作为示例,该接口方法接收一个 T1 类对象和一个 T2 类对象,通过处理后返回 R 类对象:
BiFunction<String,String ,Boolean> biFunction = String::equals;
System.out.println( biFunction.apply("a","b")); //false
7. 构造器引用( :: )
格式: ClassName :: new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
PersonNewInterface.java
@FunctionalInterface
public interface PersonNewInterface<A,B,C,D> {
D apply(A a ,B b,C c);
}
public static void main(String... args) {
// 无参构造
Supplier<Person> x = () -> new Person();
Supplier<Person> x2 = Person::new;
Person p_x2 = x2.get();
System.out.println(p_x2); // Person{name='null', age=null, score=null}
// 一个参数
Function<String,Person> f = y->new Person(y);
Function<String,Person> f2 = Person::new;
Person f2_person = f2.apply("Lucky");
System.out.println(f2_person); // Person{name='Lucky', age=null, score=null}
// 3个参数 自定义函数式接口PersonNewInterface
PersonNewInterface<String, Integer, Integer, Person> pni = (a,b,c)->new Person(a,b,c);
PersonNewInterface<String, Integer, Integer, Person> pni2 = Person::new;
Person pni_person = pni2.apply("ZekingLee", 23, 77);
System.out.println(pni_person); // Person{name='ZekingLee', age=23, score=77}
}
8. 数组引用( :: )
格式: type[] :: new
public static void main(String... args) {
Function<Integer,Person[]> f = x->new Person[x];
Function<Integer,Person[]> f2 = Person[]::new;
Person[] f_person = f2.apply(2);
System.out.println(f_person.length); // 2
}