【JDK8】新特性(一)

1. 简介

JDK8是官方发布的一个大版本, 提供了很多新特性功能给开发者使用, 包含语言、编译器、库、工具和JVM等方面的十多个新特性。 本文将介绍编码过程中常用的一些新特性. JDK8帮助文档

2.lambda表达式

概念:

语法:

注意:

        函数式接口:接口中只有一个抽象方法。

        (参数一,参数二):抽象方法的参数

        ->:分隔符

        {}:表示抽象方法的实现

代码示例:

public class Test01 {
    public static void main(String[] args) {


        // 该构造方法需要传递一个线程任务对象。Runnable类型
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt);
        t1.start();

        Runnable mt2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        };
        Thread t2 = new Thread(mt2);
        t2.start();

        // 使用Lambda表达式
        Runnable mt3 = () -> {
            System.out.println("Lambda表达式");
        };
        Thread t3 = new Thread(mt3);
        t3.start();

    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println("自定义任务接口");
    }
}

分析:

  • Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心
  • 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类
  • 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类
  • 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错
  • 而实际上,似乎只有方法体才是关键所在。 

2.1无参无返回值

 代码示例:

public class Test01 {

    public static void main(String[] args) {

        // 匿名内部类
        Swimming s = new Swimming() {
            @Override
            public void swim() {
                System.out.println("使用匿名内部类的方式");
            }
        };
        s.swim();

        // lambda表达式
        fun(() -> {
            System.out.println("使用lambda表达式");
        });

    }

    // 定义fun方法,接受一个Swimming类型的参数
    public static void fun(Swimming s) {
        s.swim();
    }
}

// 函数式接口
@FunctionalInterface
interface Swimming {
    public void swim();
}

2.2有参有返回值

代码示例:

public class Test02 {
    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        list.add(new Person("张三", 55, 180));
        list.add(new Person("李四", 49, 190));
        list.add(new Person("王五", 60, 200));
        list.add(new Person("赵六", 21, 210));

        // 对集合中的元素进行排序 按照年龄大小
        // 传统做法
        Comparator<Person> comparator = new Comparator<Person>() {
            // int:0表示新加的元素和集合中原来的比对相同
            // int:1表示新加的元素和集合中原来的比对不同 02<01
            // int:-1表示新加的元素和集合中原来的比对不同 02>01
            @Override
            public int compare(Person o1, Person o2) {
                return o2.getAge() - o1.getAge();
            }
        };
        Collections.sort(list, comparator);
        for (Person person : list) {
            System.out.println(person);
        }

        System.out.println("-------------------------------------------------------------------------------");

        Comparator<Person> comparator1 = (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();
        };
        Collections.sort(list, comparator1);
        for (Person person : list) {
            System.out.println(person);
        }


        System.out.println("-------------------------------------------------------------------------------");

        // Lambda表达式
        Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
        for (Person person : list) {
            System.out.println(person);
        }


    }

}

class Person{
    private String name;
    private int age;
    private int height;

    public Person() {
    }

    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;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }

    public Person(String name, int age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }
}

2.3详细介绍lambda表达式

  • Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
    • 左侧:(参数1,参数2…)表示参数列表
    • 右侧:{}内部是方法体
  • 注意事项
    • 形参列表的数据类型会自动推断
    • 如果形参列表为空,只需保留()
    • 如果形参只有1个,()可以省略,只需要参数的名称即可
    • 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句
    • Lambda不会生成一个单独的内部类文件 

3.函数式接口

  • 如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口,可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上
     
  • @Functionalnterface 注解检测接口是否符合函数式接口。

内置函数式接口的由来

public class Test03 {

    public static void main(String[] args) {
        Operation o = arr -> {
            int sum = 0;
            for (int n : arr) {
                sum += n;
            }
            System.out.println(sum);
        };
        fun(o);  // 调用 fun 方法并传递 lambda 表达式
    }

    public static void fun(Operation o) {
        int[] arr = {1, 2, 3, 4, 5};
        o.getSum(arr);
    }
}

@FunctionalInterface
interface Operation {
    // 求数组的和
    void getSum(int[] arr);
}

分析:

我们知道使用lambda表达式的前提是需要有函数式接口,而lambda使用时不关心接口名、抽象方法名,只关心抽象方法的参数列表和返回值类型。因此为了让我们使用lambda方便,JDK提供了大量常用的函数式接口。

常见的函数式接口

在java.util.funcation保存

3.1Consumer<T>

这个接口表示接受单个输入参数并且不返回任何结果的操作。它通常用于需要对单个参数执行某些操作,但不需要返回值的情况。

        void accept(T t);

public class Test {
    public static void main(String[] args) {
        Consumer<Double> c = t -> {
            System.out.println("按摩消费了:" + t + "元");
        };
        fun01(c,1000.0);
    }

    public static void fun01(Consumer<Double> consumer,double money){
        consumer.accept(money);
    }

}

3.2Supplier<T>供给型函数式接口

这个接口代表一个供给型接口,它不接受任何参数,但会返回一个结果。接口定义非常简单,只有一个抽象方法:

           T get();

public class Test02 {
    public static void main(String[] args) {
        Supplier<Integer> supplier = ()-> (int)(Math.random()*100);
        fun(supplier);
    }

    public static void fun(Supplier<Integer> supplier){
        Integer num = supplier.get();
        System.out.println("内容为:"+num);
    }
}

3.3Function<T,R>函数型函数式接口

这个接口表示一个函数,接受一个类型为 T 的参数,并返回一个类型为 R 的结果。接口定义如下:

        R apply(T t);

public class Test03 {
    public static void main(String[] args) {
        fun(s -> s.toUpperCase(),"hello");
    }

    public static void fun(Function<String ,String> function,String msg){
        String s = function.apply(msg);
        System.out.println(s);
    }

}

3.4Predicate<T>

这个接口表示一个接受单个参数并返回布尔值的断言函数。它用于对传入的参数进行判断,并返回一个布尔值结果。

        boolean test(T t);

当传入一个参数时,需要对该参数进行判断时,则需要这种函数。

public class Test04 {
    public static void main(String[] args) {
        fun(s->s.length()>3?true:false,"撒大大大v啊");
    }

    public static void fun(Predicate<String> predicate,String name){
        boolean b = predicate.test(name);

        System.out.println("该名称的长度是否长啊"+b);
    }

}

4. 方法引用

我们用Lambda表达式来实现==匿名方法==。但有些情况下,我们用Lambda表达式仅仅是调用==一些已经存在的方法,除了调用方法外,没有其他任何多余的动作==,在这种情况下,我们倾向于通过方法名来调用它,而Lambda表达式可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁、更容易理解。==方法引用可以理解为Lambda表达式的另外一种表现形式。方法引用要比lambda表达式语法更加简洁==

方法引用: 理解为Lambda表达式的另一种表现。它的语法更加简洁。

方法引用使用的前提: lambda表达式中调用的是已经存在的方法,除了调用方法外,不能有任何其他操作,才可以使用方法引用。

4.1 lambda表达式的冗余

public class Test01 {
    public static void main(String[] args) {
        Consumer<Integer[]> consumer = arr -> {
            int sum = 0;
            for (Integer integer : arr) {
                sum += integer;
            }
            System.out.println(sum);
        };
        fun(consumer);
    }
    public static void fun(Consumer<Integer[]> consumer){
        Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
        consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
        int sum = 0;
        for (Integer integer : arr) {
            sum += integer;
        }
        System.out.println(sum);
    }
}

分析:


如果我们在Lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要再写重复逻辑?可以直接“引 用”过去就好了: ---方法引用

public class Test01 {
    public static void main(String[] args) {

        Consumer<Integer[]> consumer1 = Test01::sum;
        fun(consumer1);
    }
    public static void fun(Consumer<Integer[]> consumer){
        Integer[] arr = {1,2,3,4,5,6,7,8,9,10};
        consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
        int sum = 0;
        for (Integer integer : arr) {
            sum += integer;
        }
        System.out.println(sum);
    }
}

4.2 什么是方法引用?

方法引用允许你直接引用现有方法(静态方法、实例方法或构造方法),而不必像 lambda 表达式那样完全重新实现一个功能。它的语法基本上是 :: 符号,后跟方法的名称

方法引用的分类

4.3 实例方法引用

实例方法引用,顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化静态方法引用类无需实例化,直接用类名去调用。

 案例:计算一个字符串列表中每个字符串的长度。

public class Test{
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("hello", "world", "java", "method", "reference");

        // 使用实例方法引用,计算字符串长度
        Function<String, Integer> stringLength = String::length;
        List<Integer> lengths = strings.stream()
                                       .map(stringLength)
                                       .collect(Collectors.toList());

        // 输出字符串长度列表
        lengths.forEach(System.out::println);
    }
}

4.4 对象方法引用

 案例:将一个字符串列表转换为大写字母。

public class Test01{
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("hello", "world", "java", "method", "reference");

        // 使用对象方法引用,将字符串转换为大写
        Function<String, String> toUpperCase = String::toUpperCase;
        List<String> upperCaseStrings = strings.stream()
                                               .map(toUpperCase)
                                               .collect(Collectors.toList());

        // 输出转换后的字符串列表
        upperCaseStrings.forEach(System.out::println);
    }
}

4.5 构造方法引用

案例:根据名字创建 Person 对象的列表。

public class Test03{
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 使用构造方法引用创建 Person 对象
        Function<String, Person> personConstructor = Person::new;
        List<Person> people = names.stream()
                                   .map(personConstructor)
                                   .collect(Collectors.toList());

        // 输出 Person 对象列表
        people.forEach(System.out::println);
    }
}
class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "'}";
    }
}

还有一部分没有写完!晚会补上!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值