JDK新特性01-Lambda表达式、常用函数式接口
文章目录
1、Lambda表达式
1.1、格式组成:
(参数类型 参数名称)->{
代码体;
}
说明:
- (参数类型 参数名称):参数列表
- {代码体;}:方法体
- ->:箭头,分割参数列表和方法体
1.2、使用:
1.2.1、无参无返回:
定义接口:
public interface UserService {void show();
}
主线程:
public static void main(String[] args) {getShow(new UserService() {@Overridepublic void show() {System.out.println("show方法执行了。。。");}});getShow(()->{System.out.println("lambda表达式执行show方法");});}public static void getShow(UserService userService){userService.show();}
1.2.2 有参有返回
public static void main(String[] args) {ArrayList<User> users = new ArrayList<>();users.add(new User("张三",33,175));users.add(new User("李四",30,170));users.add(new User("王五",23,168));users.add(new User("六六",26,198));
// Collections.sort(users, new Comparator<User>() {
// @Override
// public int compare(User o1, User o2) {
// return o1.getAge()-o2.getAge();
// }
// });
// for (User user : users) {
// System.out.println(user);
// }System.out.println("---------lambda表达式");Collections.sort(users,(User o1,User o2)->{return o1.getAge()-o2.getAge();});for (User user : users) {System.out.println(user);}}
1.3 省略写法:
规则:
- 小括号内的参数类型可以省略
- 如果小括号内有且仅有一个参数,则小括号可以省略
- 如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号
eg:
public static void main(String[] args) {goStudent((String name, Integer age) -> {return name + "ppp" + age;});System.out.println("----省略格式");goStudent((name, age) -> name + "ppp" + age);System.out.println("-------------");goOrder((String name)->{System.out.println("李四6666");return 666;});System.out.println("省略写法");goOrder((name)->666);}public static void goStudent(StudentService service){service.show("张三",22);}public static void goOrder(OrderService service){service.show("李四");}
1.4 原理:
Lambda表达式在程序运行的时候会形成一个类,这个类中新增了一个方法,该方法的方法体就是Lambda表达式中的代码,同时还会形成一个匿名内部类,实现接口,重写抽象方法,在接口中重写方法会调用新生成的方法。
1.5 与匿名函数的区别
1、所需类型不一样
- 匿名内部类的类型可以是类,抽象类,接口.
- Lambda表达式需要的类型必须是接口
2、抽象方法的数量不一样
- 匿名内部类所需的接口中的抽象方法的数量是随意的
- Lambda表达式所需的接口中只能有一个抽象方法
3、实现原理不一样
- 匿名内部类是在编译后形成一个class
- Lambda表达式是在程序运行的时候动态生成class
2、新增接口方法
2.1、新增前后区别:
jdk8之前:
interface 接口名{
静态常量;
抽象方法;
}
jdk8之后
interface 接口名{
静态常量;
抽象方法;
默认方法;
静态方法;
}
2.2 默认方法的增加
1 、 增加原因:
jdk8之前的接口只有抽象方法和静态常量,会存在一些问题,当想要增加新的抽象方法的时候,实现类需要实现这个接口的所有方法,不利于接口的拓展。
2、接口默认的语法格式:
interface 接口名{
修饰符 default 返回值类型 方法名{
方法体;
}
}
3、接口中默认方法的使用
两种方式:
1、实现类直接调用接口的默认方法
2、实现类重写接口 的默认方法
2.3、静态方法
语法规则:
interface 接口名{
修饰符 static 返回值类型 方法名{
方法体;
}
}
2.4、两者区别
1、默认方法可以通过实例调用,静态方法通过接口名调用
2、默认方法可以被继承,实现类可以直接调用接口默认方法,也可以重写接口默认方法‘’‘
3、静态方法不能被继承,实现类不能重写接口的静态方法 ,只能使用接口名调用
3、四大常用函数式接口
1、Supplier接口:
Supplier函数式接口是Java 8中的一个内置接口,它表示一个供应商,用于提供一个结果。Supplier函数式接口没有任何入参,只负责返回一个结果。Supplier接口只包含一个方法get(),该方法不接收任何参数,返回一个泛型T的结果。
源代码:
public interface Supplier<T> {/* Gets a result. @return a result*/T get();
}
Supplier函数式接口可以被用于许多场景,例如在需要创建一个对象时,可以使用Supplier来提供一个工厂方法,以便在需要时生成对象。另外,当需要延迟计算某个结果时,也可以使用Supplier来实现懒加载。eg:
public class SupplierTest {public static void main(String[] args) {fun(()->{int [] arr = {1,2,32,43,12,4,3,89};Arrays.sort(arr);return arr[arr.length-1];});}public static void fun(Supplier<Integer> supplier){// get()是一个无参有返回值的抽象方法Integer max = supplier.get();System.out.println("最大值是"+max);}
}
这里定义了一个fun()方法,这个方法接收了一个Supplier类型的参数,然后输出该参数提供的最大值,其实我们也可以直接使用Lambda表达式或者方法来创建。如下:
int[] arr = {1,2,32,43,12,4,3,89};
Supplier<Integer> supplier = () -> Arrays.stream(arr).max().orElse(0);
int max = supplier.get();
System.out.println("数组最大值是:" + max);
其中的orElse(0)的意思是如果数组为空就返回0
2、Consumer接口
Consumer接口是Java 8中的一个函数式接口,它定义了一个接受一个参数并且不返回任何结果的函数。。它有一个抽象方法void accept(T t),表示对给定的参数执行操作。
源代码:
public interface Consumer<T> {/* Performs this operation on the given argument. @param t the input argument*/void accept(T t);
}
Consumer接口通常用于需要对某些对象执行操作而不需要返回值的场合,比如对集合中的元素进行遍历并执行某些操作。eg:将所定义的字符串转换为小写
public class ConsumerTest {public static void main(String[] args) {fun((msg)->{System.out.println(msg.toLowerCase(Locale.ROOT));});}public static void fun(Consumer<String> consumer){consumer.accept("HELLO WORLD!!!");}
}
直接使用lambda表达式:(遍历数组)
List<String> names = Arrays.asList("Tom", "Jerry", "Mickey");
Consumer<String> printName = name -> System.out.println(name);
names.forEach(printName);
Consumer接口中还有一个默认方法andThen(),该方法接受一个Consumer类型的参数,返回一个新的Consumer类型对象,该对象将当前Consumer对象的操作和传入的Consumer对象的操作连续执行。简单的来说就是先做一个操作,再做一个操作,实现组合。
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
Consumer<String> printLowerCase = str ->System.out.println(str.toLowerCase());Consumer<String> printBoth = printUpperCase.andThen(printLowerCase);printBoth.accept("Hello World"); // 输出 "HELLO WORLD" 和 "hello world"
这里定义了两个Consumer对象,一个用于打印大写的字符串,一个用于打印小写的字符串,用andThen连接起来,得到一个新的Consumer对象,然后先执行大写的,在执行小写的。
3、Funtion
有参有返回值,这个接口是根据一个类型的数据再得到另外一个类型的数据,前者称为前置条件,后者称为后置条件 ,源代码:
public interface Function<T, R> {/* Applies this function to the given argument. @param t the function argument* @return the function result*/R apply(T t);
}
其中,T表示函数的输入参数类型,R表示函数的返回值类型。apply()方法接收一个T类型的参数并返回一个R类型的值,表示该函数的行为或功能。eg:
ist<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Function<Integer, Integer> square = x -> x * x;
List<Integer> squares = numbers.stream().map(square).collect(Collectors.toList());
这里是把一个数组集合里面 的每个对象映射为平方,然后将所有得到的数据收集成一个数组。
该接口还有两个默认方法和一个静态方法 :
静态方法:
identify():返回一个恒等函数,即接收一个参数并返回该参数本身。
默认方法:
andThen():与Consumer里面的使用方法一样
compose():与andThen()一样,只是顺序相反
4、Predicate
有参返回布尔值,源代码:
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);}
Predicate接口可以用于函数式编程中的过滤器、映射等场景,可以用于对集合中的元素进行筛选、过滤或转换操作。例如,可以使用Predicate接口的实现来过滤出符合某些条件的元素,或者将一个集合中的元素进行转换后再进行某些操作。eg: 这里是对数据做了一个筛选,只留下了以字母a开头的元素。
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Predicate<String> startsWithA = str -> str.startsWith("a");
List<String> filteredList=list.stream().filter(startsWithA).collect(Collectors.toList());
该接口有着三个默认方法和一个静态方法:
默认方法是and()、nagate()、or(),举个简单的例子:
public class PredicateTest2 {public static void main(String[] args) {fun(msg->{return msg.contains("h");},msg2->{return msg2.contains("w");});}public static void fun(Predicate<String> p1,Predicate<String> p2){// p1 包含H 同时 p2包含wSystem.out.println(p1.and(p2).test("hello w"));// p1 包含H 或者 p2包含wSystem.out.println(p1.or(p2).test("hello"));// p1不包含HSystem.out.println(p1.negate().test("hello"));}
}
静态方法是isEqual(),它的作用是根据对象的equals方法比较两个对象是否相等。如果两个对象相等,则返回true,否则返回false。