(o1,o2)->Integer.compare(o1,o2);
//example 1: 不用lambda表达式
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(comparator.compare(71, 22)); // result:1
//example 2: 用lambda表达式
Comparator<Integer> comparator1 = (o1, o2) -> Integer.compare(o1,o2);
System.out.println(comparator1.compare(22, 22)); // result:0
//example 3: 用方法引用
Comparator<Integer> comparator2 = Integer ::compare;
System.out.println(comparator2.compare(11, 44)); // result:0
- 格式:
->左边:lambda
的形参列表(接口中抽象方法的形参列表)
->右边:lambda
体(重写的抽象方法的方法体)
lambda本质:接口的实例 - lambda使用:
->左边:lambda
的形参中参数类型可以省略,其中只有一个参数,可以省区小括号()
->右边:lambda
体 用{}包裹,若:lambda
只有一条执行语句,则{}可以省略,若是return
语句,则省略{}时,必须省略return
关键字。
//1. 无参
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("ddd");
}
};
runnable.run(); //调用run()方法
Runnable runnable1 = () -> System.out.println("ddd"); //lambda
runnable1.run();
//2. 有一个参数,没有返回值
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("consumer--" + s);
}
};
consumer.accept("abc"); //result:consumer--abc
//Consumer<String> consumer1 = (String s) -> {
Consumer<String> consumer1 = (s) -> { //省去String,叫做类型推断
System.out.println("consumer--" + s);
};
consumer1.accept("123"); //result: consumer--abc
//当lambda体只有一句语句时 {} 可以省略
Consumer<String> consumer2 = (s) -> System.out.println("consumer--" + s);;
consumer2.accept("456"); //result: consumer--456
// 3. 参数类型只有一个,()可以省略
Consumer<String> consumer1 = s -> { //省去()
System.out.println("consumer--" + s);
};
consumer1.accept("123"); //result: consumer--abc
// 4. 只有一条执行语句,则{}可以省略,若是`return `语句,则省略{}时,必须省略`return`关键字。
Comparator<Integer> comparator3 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 + o2;
}
};
System.out.println(comparator3.compare(1, 2)); //result: 3
Comparator<Integer> comparator4 = (o1,o2) -> o1 + o2;
System.out.println(comparator4.compare(1, 3)); ////result: 4
- 对于只有一个抽象方法的接口, 需要这种接口的对象时, 就可以提供一个
lambda
表达式。 这种接口称为函数式接口(functional interface )
。
函数式接口:
//1. Consumer<T>
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after){
//see resource code
}
}
//2. Supplier<T>
@FunctionalInterface
public interface Supplier<T> {
T get();
}
// 3. Function<T, R>
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
...
}
// 4. Predicate<T>
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {}
default Predicate<T> negate(){}
default Predicate<T> or(Predicate<? super T> other){}
static <T> Predicate<T> isEqual(Object targetRef){}
}
- 方法引用:
object::instanceMethod
Class::staticMethod
Class::instanceMethod
在前 2 种情况中, 方法引用等价于提供方法参数的 lambda
表达式。 如:System.out::println
等价于 x-> System.out.println(x)
。 类似地,Math::pow
等价于(x,y)-> Math.pow(x, y)。
对于第 3 种情况, 第 1 个参数会成为方法的目标。例如,String::compareToIgnoreCase
等
同于 (x, y)-> x.compareToIgnoreCase(y)
/**
① Consumer中的 void accept(T t);
② PrintStream中的 println(T t);
要求:①中的参数列表和②中参数列表一样,①中的返回值和②中的返回值一样
*/
//1. object::instanceMethod
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("abc"); //result: abc
PrintStream ps = System.out;
Consumer<String> consumer1 = ps::println;
consumer1.accept("ddd"); //result: ddd
/**
Comparator中的int compare(T t1, T t2);
Integer中的 int compare(T t1, T t2) 参数列表和返回值一样
*/
// 2. Class::staticMethod
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(comparator.compare(22, 22)); //result: 0
Comparator<Integer> comparator1 = Integer::compare;
System.out.println(comparator1.compare(23, 32)); //result: -1
/**
Comparator中的int compare(T t1, T t2);
String 中的 int compareTo(T t);
*/
// 3. Class::instanceMethod
Comparator<String> comparator = (o1, o2) -> o1.compareTo(o2);
System.out.println(comparator.compare("df", "fd")); //result: -2
Comparator<String> comparator1 = String::compareTo;
System.out.println(comparator1.compare("df", "df")); //result: 0
- 构造器引用:和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致,抽象方法的返回值类型即为构造器所属的类的类型。如:
Person :: new
,它是Person构造器的一个引用。 - 数组引用:将数组看成一个类即可。就和构造器一样了。如:
int[] :: new
,相当于lambda
表达式的length -> new int[Length]
。 - 变量作用域:
public static void repeat(String text, int count){
for (int i = 1; i <= count; i++){
ActionListener listener = event ->{
System.out.pn'nt1n(i + ": " + text);
// Error: Cannot refer to changing i
};
new Timer(1000, listener).start();
}
}
}
这里有一条规则:lambda 表达式中捕获的变量必须实际上是最终变量 ( effectivelyfinal)。实际上的最终变量是指, 这个变量初始化之后就不会再为它赋新值。在这里,text 总是指示同一个 String 对象,所以捕获这个变量是合法的。不过,i 的值会改变,因此不能捕获 i。