JDK新特性01-Lambda表达式、常用函数式接口

文章介绍了Java8中的Lambda表达式,包括格式、使用场景、省略写法和与匿名函数的区别。此外,还详细讲解了接口新增的默认方法和静态方法,以及四大常用函数式接口——Supplier、Consumer、Function和Predicate的用途和用法。
摘要由CSDN通过智能技术生成

1、Lambda表达式

1.1、格式组成:

(参数类型 参数名称)->{
代码体;
}

说明:

  • (参数类型 参数名称):参数列表
  • {代码体;}:方法体
  • ->:箭头,分割参数列表和方法体

1.2、使用:

1.2.1、无参无返回:

定义接口:

public interface UserService {
    void show();
}

主线程:

public static void main(String[] args) {
        getShow(new UserService() {
            @Override
            public 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包含w
        System.out.println(p1.and(p2).test("hello w"));
        // p1 包含H 或者 p2包含w
        System.out.println(p1.or(p2).test("hello"));
        // p1不包含H
        System.out.println(p1.negate().test("hello"));
    }
}

静态方法是isEqual(),它的作用是根据对象的equals方法比较两个对象是否相等。如果两个对象相等,则返回true,否则返回false。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值