作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)
一、概述
以前我们在实现接口时,一般是写一个实现类,然后重写需要调用的方法,如果不想创建实现类,就使用匿名内部类来重写方法。
public interface MyInterface {
void test();
}
实现类重写方法
public class MyInterfaceImpl implements MyInterface {
@Override
public void test() {
System.out.println("重写了该方法!!");
}
}
匿名内部类重写方法
MyInterface myInterface = new MyInterface() {
@Override
public void test() {
System.out.println("匿名内部类重写方法!!!");
}
};
在有了lambda表达式后,可以简化接口的实现,达到不创建新的实现类和使用匿名内部类,使用简单的代码就可以实现接口。
MyInterface myInterface1 = () -> System.out.println("lambda重写方法");
二、lambda表达式的格式
(params…) -> {operation}
表达式分为三个部分:
1.左边是参数,即接口方法的入参,如果是无参的,就只需要(),参数的类型可以省略不写
2.中间的是lambda的符号,-> 意为(gose to)
3.右边是方法实现的方法体,就相当于我们实现接口时,在方法体中写的代码,如果只有一句,则可以不要{},有返回值的也不需要return;如果有多句代码,则需要大括号,有返回值的接口,需要加上return;
三、Java内置的函数式接口
1、函数式接口:在jdk8以前,接口只能有抽象方法,不能有带有方法体的方法,但是在jdk8之后,接口也可以有非抽象方法,只需要在方法定义时,加上default,如果接口只能有一个抽象方法,在接口加上@FunctionalInterface注解,只有一个抽象方法的接口叫做函数式接口。
2、内置的函数式接口,关注每个接口的方法,主要区别就是方法的参数和返回值,这样我们就可以不用自己去定义接口,只需要使用lambda表达式去实现它。
(1)、
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
以前需要排序集合的做法
List<User> list = new ArrayList<>();
User user1 = new User("里斯",16);
User user2 = new User("嗷嗷",56);
User user3 = new User("哈哈",23);
User user4 = new User("奥奥",16);
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.sort(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
if(o1.getAge()>o2.getAge()){
return 1;
}else if(o1.getAge().equals(o2.getAge())){
return 0;
}else {
return -1;
}
}
使用lambda表达式
list.sort((u1,u2) -> Integer.compare(u1.getAge(),u2.getAge()));
这里我们看到方法的实现是调用了另一个方法,前提是这个方法和需要实现的方法参数和返回值一样,
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
(2)、
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
这个接口有一个参数,返回值为boolean,来看一下这个接口在Collection接口中的用法
//这个方法是移除集合中满足条件的元素,注意这个方法是在接口中,所以加了default后就可以有方法体了。
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
以前的调用形式
List<User> list = new ArrayList<>();
User user1 = new User("里斯",16);
User user2 = new User("嗷嗷",56);
User user3 = new User("哈哈",23);
User user4 = new User("奥奥",16);
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//使用匿名内部类来实现方法
list.removeIf(new Predicate<User>() {
@Override
public boolean test(User user) {
if(user.getAge()>20){
return true;
}
return false;
}
});
使用lambda表达式:
List<User> list = new ArrayList<>();
User user1 = new User("里斯",16);
User user2 = new User("嗷嗷",56);
User user3 = new User("哈哈",23);
User user4 = new User("奥奥",16);
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//表达式左边是参数u,类型可以省略,不省略的话就是User u,右边是方法体,
//返回的是boolean值,可以看到参数和返回值与Predicate接口的test
//方法是一致的。
list.removeIf(u -> u.getAge()>20);
(3)、
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
集合的foreach方法参数是这个接口,循环集合的元素,然后调用了该接口的accept方法。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
使用lambda表达式循环输出集合元素
list.forEach(System.out::println);
println方法入参和返回值与accept一样,可以使用该方法的方法体直接实现accept方法。
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
注意:
::双冒号可以调用接口的方法