- JDK8出现的
- 函数式接口(Functional Interface)
任何接口,如果只有一个显式声明的抽象方法,那么就是函数式接口
一般都会用@FunctionalInterface注解表示- 对于函数式接口,可以通过Lambda表达式来创建该接口的对象
- 举例如下:
@FunctionalInterface public interface Runnable { void run(); } public interface Callable{ V call() throws Exception; } public interface ActionListener { void actionPerformed(ActionEvent e); } public interface Comparator { int compare(T o1, T o2); boolean equals(Object obj); }
- Lambda表达式演化过程
2.与Comparator接口有关的Lambda表达式
- 先给出结论:Comparator接口是函数式接口
- Comparator接口的源码:
public interface Comparator{ int compare(T o1, T o2); boolean equals(Object obj); default Comparator reversed() { return Collections.reverseOrder(this); } public static Comparator comparing( Function super T, ? extends U> keyExtractor, Comparator super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); } ... }
- 疑问:Comparator接口中有两个抽象方法和若干个带default关键字的方法,为什么仍是函数式接口呢?
1、default关键字可以让接口中的方法可以有默认的函数体,当一个类实现这个接口时,可以不用去实现这个方法。由于默认方法已经有了实现,所以它们不是抽象方法。
2、函数式接口中可以有静态方法,一个或者多个静态方法不会影响接口成为函数式接口。
3、重写了超类Object类中任意一个public方法的方法并不算接口中的抽象方法。
3.与创建线程有关的Lambda表达式
1、一个λ表达式只有在转型成一个函数式接口后才能被当做Object使用
//可以用一个λ表达式为一个函数式接口赋值,再赋值给一个Object
Runnable r1 = () -> {
System.out.println("Hello Lambda!");
};
Object obj= r1;
//ERROR! Object is not a functional interface!
Object obj = () -> {
System.out.println("Hello Lambda!");
};
//correct
//必须显式的转型成一个函数式接口
Object o = (Runnable) () -> {
System.out.println("hi");
};
2、为什么可以直接这样定义一个线程?
//匿名内部类形式
Thread oldSchool = new Thread( new Runnable () {
@Override
public void run() {
System.out.println("This is from an anonymous class.");
}
});
Thread thread = new Thread(() -> {
System.out.println("This is from an anonymous method (lambda exp).");
});
4.与集合有关的Lambda表达式
- 回顾一下集合中的遍历方式
1、for循环
public class For {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
}
}
2、iterator
public class IteratorTest {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
System.out.println(s);
}
}
}
3、增强for循环
public class IteratorTest {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
for (String s : list) {
System.out.println(s);
}
}
}
4、增强for循环+Lambda表达式
- 为什么可以用Lambda表达式?
1、JDK1.8中更新了Lambda表达式,查询Iterable接口源码可得:
public interface Iterable{ Iterator iterator(); default void forEach(Consumer super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } } 2、对于默认方法forEach,形式参数类型Consumer super T>,查询其源码可得:
@FunctionalInterface public interface Consumer{ void accept(T t); default Consumer andThen(Consumer super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } } 发现Consumer接口是一个函数式接口,所以我们可以用Lambda表达式传入一个函数式接口对象!
public class IteratorTest {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.forEach(s -> System.out.println(s));
}
}
还有一个对其改进的方法
public class IteratorTest {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.forEach(System.out::println);
}
}



