Lambda
Lambda 表达式
java8新增特性函数式编程初探
Lambda初级形态
package lambda;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "name="+name+";age="+age;
}
}
根据年龄对学生进行从小到大排序
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student("大明",6));
list.add(new Student("李梅",3));
list.add(new Student("莉莉",10));
list.add(new Student("山姆",19));
list.add(new Student("李雷",15));
Collections.sort(list,new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
});
System.out.println(list);
}
通过集合工具类提供的排序方法,传入自定义比较器进行排序,一种中规中矩写法。
下面通过java8新特性做一次
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student("大明",6));
list.add(new Student("李梅",3));
list.add(new Student("莉莉",10));
list.add(new Student("山姆",19));
list.add(new Student("李雷",15));
Collections.sort(list,(o1,o2)->o1.getAge()-o2.getAge());
System.out.println(list);
}
那为什么可以这样写呢?
java8新增一个很重要特性:Lambda表达式,亦作闭包;规定仅包含一个抽象方法的接口为函数式接口,用@FunctionalInterface进行标明,仅仅是告诉编译器该接口是一个函数式接口,当接口不符合函数式接口定义会编译报错,该注解不是必须的。
那么让我们追根溯源去看下Comparator接口
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
default <U> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
return thenComparing(comparing(keyExtractor, keyComparator));
}
default <U extends Comparable<? super U>> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor)
{
return thenComparing(comparing(keyExtractor));
}
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
return thenComparing(comparingInt(keyExtractor));
}
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
return thenComparing(comparingLong(keyExtractor));
}
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
return thenComparing(comparingDouble(keyExtractor));
}
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
return Collections.reverseOrder();
}
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
}
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(true, comparator);
}
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(false, comparator);
}
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator<T> & Serializable)
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}
public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
}
public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
}
}
什么鬼???问号脸!!!怎么还有一堆default、static修饰的方法,而且还有一个抽象方法boolean equals(Object obj),难道规则就是用来打破的么?
- 默认方法
函数式接口可以包含默认方法,因为默认方法不可以是抽象方法,其有一个默认实现,所以是符合函数式接口定义。 - 静态方法
函数式接口可以包含静态方法,因为静态方法不可以是抽象方法,是一个已经实现了的方法,所以是符合函数式接口定义。 - boolean equals(Object obj)
可以包含Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类。
Lambda语法格式:
(参数) -> {表达式;}
Lambda语法特征:
可选类型声明:可以不用声明参数类型,编译器可以根据上下文判断参数类型
可选参数圆括号:仅有一个参数无需圆括号
可选大括号:表达式仅包含一个语句,可以不写大括号以及语句末尾的分号
可选返回关键字:表达式仅包含一个语句,可以不写返回关键字return
1.多参数栗子
Collections.sort(list,(o1,o2)->o1.getAge()-o2.getAge());
2.无参数栗子
new Thread(() -> System.out.println("我是线程:"+Thread.currentThread().getName())).start();
3.单个参数栗子
public static void main(String[] args) {
//Consumer:提供任意一种类型的参数,返回空值。 void accept(T t);
Consumer con = x -> System.out.println(x);
con.accept("666");
}
jdk8中新增函数式接口包:java.util.function
Runnable r = () -> System.out.printf(“say hello”); //没有输入参数,也没有输出
Supplier sp = () -> “hello”; //只有输出消息,没有输入参数
Consumer cp = r -> System.out.printf(r); //有一个输入参数,没有输出
Function<Integer, String> func = r -> String.valueOf(r); //有一个输入参数 有一个输出参数
BiFunction<Integer, Integer, String> biFunc = (a, b) -> String.valueOf(a + b); //有两个输入参数 有一个输出参数
BiConsumer<Integer, Integer> biCp = (a, b) -> System.out.printf(String.valueOf(a + b)); //有两个输入参数 没有输出参数
……
Lambda高级形态
方法引用
1.静态方法引用:ClassName::methodName
BiFunction<Integer,Integer,Integer> result = Integer::sum;
result.apply(1, 2);
or
BiFunction<Integer, Integer, Integer> con = (a,b)->Integer.sum(a, b);
con.apply(1,2);
2.实例上的实例方法引用:instanceReference::methodName
Set set = new HashSet();
set.add(“666”);
Predicate pr = set::contains;
pr.test(“666”);
pr.test(“233”);
or
Predicate p = ars -> set.contains(args);
p.test(“666”);
p.test(“233”);
3.构造方法引用:Class::new
Function<String, BigDecimal> f = b->new BigDecimal(b);
System.out.println(f.apply(“666”));
or
Function<String,BigDecimal> ff = BigDecimal::new;
System.out.println(ff.apply(“77”));
4.数组构造方法引用:typeName[]::new
IntFunction<int[]> i = int[]::new;
i.apply(5);
System.out.println(i.apply(1)[0]);
另:lambda表达式中可以读取并修改所在类成员变量;可读取所在方法局部变量但无法修改,而且当其读取局部变量时该变量将变为final修饰从而无法被修改。
总结
1.Lambda表达式使得代码更简洁,思路更清晰。
2.初级用法(参数)->{表达式},有三种用法。
3.高级用法ClassName::methodName,主要有四种用法
参考资料
- https://www.runoob.com/java/java8-lambda-expressions.html
- https://www.cnblogs.com/andywithu/p/7357069.html
- https://baijiahao.baidu.com/s?id=1614680282522143196&wfr=spider&for=pc
- https://shmilyaw-hotmail-com.iteye.com/blog/2251821