• JDK8的特性


    1.Lambda表达式

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

    (参数1,参数2): 抽象方法的参数

    ->: 分隔符

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

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. //该构造方法需要传递一个线程任务对象。Runnable类型
    4. My task=new My();
    5. Thread t1=new Thread(task);
    6. t1.start();
    7. //匿名内部类
    8. Runnable task02=new Runnable() {
    9. @Override
    10. public void run() {
    11. System.out.println("这时匿名内部类方式的任务对象");
    12. }
    13. };
    14. Thread t2=new Thread(task02);
    15. t2.start();
    16. }
    17. }
    18. class My implements Runnable{
    19. @Override
    20. public void run() {
    21. System.out.println("自定义任务接口类");
    22. }
    23. }

    分析: 

    • Thread 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心

    • 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类

    • 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类

    • 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错

    • 而实际上,似乎只有方法体才是关键所在。

    可以使用lambda表示完成上面的要求

    1. //lambda表达式
    2. Runnable task03 = ()-> {
    3. System.out.println("这是使用Lambda表达式完成的");
    4. };
    5. Thread t3=new Thread(task03);
    6. t3.start();

    前提:必须是函数式接口。

    简化匿名内部类的使用,语法更加简单。

    1.1.无参无返回值

    1. public class Test {
    2. public static void main(String[] args) {
    3. //匿名内部对象
    4. People people1 = new People() {
    5. @Override
    6. public void eat() {
    7. System.out.println("匿名内部对象");
    8. }
    9. };
    10. fun(people1);
    11. //lambda表达式
    12. People people2 = () -> {
    13. System.out.println("lambda表达式");
    14. };
    15. fun(people2);
    16. }
    17. public static void fun(People p){
    18. p.eat();
    19. }
    20. }
    21. //函数式接口
    22. interface People{
    23. public void eat();
    24. }

    1.2.有参有返回值

    举例演示 java.util.Comparator 接口的使用场景代码,其中的抽象方法定义为:

    • public abstract int compare(T o1, T o2);

    当需要对一个对象集合进行排序时, Collections.sort 方法需要一个 Comparator 接口实例来指定排序的规则。

    1. public class Test {
    2. public static void main(String[] args) {
    3. List list = new ArrayList<>();
    4. list.add(new People("张三",18,178));
    5. list.add(new People("李四",19,177));
    6. list.add(new People("王五",20,176));
    7. list.add(new People("赵六",21,175));
    8. //对集合中的元素进行排序 按照年龄从大到小。
    9. Comparator comparator = (People o1, People o2) -> {
    10. return o2.getAge()- o1.getAge();
    11. };
    12. Collections.sort(list,comparator);
    13. for (People p: list) {
    14. System.out.println(p);
    15. }
    16. }
    17. }
    18. class People{
    19. private String name;
    20. private int age;
    21. private double height;
    22. @Override
    23. public String toString() {
    24. return "People{" +
    25. "name='" + name + '\'' +
    26. ", age=" + age +
    27. ", height=" + height +
    28. '}';
    29. }
    30. public People(String name, int age, double height) {
    31. this.name = name;
    32. this.age = age;
    33. this.height = height;
    34. }
    35. public String getName() {
    36. return name;
    37. }
    38. public void setName(String name) {
    39. this.name = name;
    40. }
    41. public int getAge() {
    42. return age;
    43. }
    44. public void setAge(int age) {
    45. this.age = age;
    46. }
    47. public double getHeight() {
    48. return height;
    49. }
    50. public void setHeight(double height) {
    51. this.height = height;
    52. }
    53. }

    1.3.详解Lambda表达式

    2.函数式接口

    内置函数接口的由来

    1. public class Test {
    2. public static void main(String[] args) {
    3. People p = arr -> {
    4. int sum = 0;
    5. for (int n: arr) {
    6. sum += n;
    7. }
    8. System.out.println("数组的和为:"+sum);
    9. };
    10. fun(p);
    11. }
    12. public static void fun(People people){
    13. int[] arr = {1,2,3,4,5,6,7};
    14. people.getSum(arr);
    15. }
    16. }
    17. /**
    18. * 标识某个接口是函数式接口 只能有一个 public 接口
    19. */
    20. @FunctionalInterface
    21. interface People{
    22. public abstract void getSum(int[] arr);
    23. }

    分析:

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

    常见的函数式接口:

    2.1.Consumer 消费型接口

    有参数,无返回值。  

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. Consumer consumer = t -> {
    4. System.out.println("花了"+t+"元");
    5. };
    6. fun01(consumer,2000);
    7. }
    8. public static void fun01(Consumer consumer,double money){
    9. consumer.accept(money);
    10. }
    11. }

    2.2.Supplier供给型函数式接口

    T:表示返回结果的泛型

    无参,想有返回结果的函数式接口时   T.get();

    1. public class Test02 {
    2. public static void main(String[] args) {
    3. fun(() -> new Random().nextInt(10));
    4. }
    5. public static void fun(Supplier supplier){
    6. Integer i = supplier.get();
    7. System.out.println("内容为:"+i);
    8. }
    9. }

    2.3.Function 函数型函数式接口

    T: 参数类型的泛型

    R: 函数返回结果的泛型

    有参,有返回 值时。

    1. public class Test03 {
    2. public static void main(String[] args) {
    3. //将字符串小写转大写
    4. fun((t) -> {
    5. return t.toUpperCase();
    6. },"hello world");
    7. //求字符串的长度;
    8. length((l) -> {
    9. return l.length();
    10. },"hello world");
    11. }
    12. public static void fun(Function function,String msg){
    13. String f = function.apply(msg);
    14. System.out.println("结果为:"+f);
    15. }
    16. public static void length(Function function,String msg){
    17. Integer i = function.apply(msg);
    18. System.out.println("长度为:"+i);
    19. }
    20. }

    2.4.Predicated 断言型接口

    T: 参数的泛型

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

    1. public class Test04 {
    2. //判断名字的长度是否大于 3
    3. public static void main(String[] args) {
    4. fun((t) ->{
    5. return t.length()>3?true:false;
    6. },"sssss");
    7. }
    8. public static void fun(Predicate predicate,String name){
    9. boolean b = predicate.test(name);
    10. System.out.println("结果为:"+b);
    11. }
    12. }

    3.方法引用

    lambda表达式有时会导致冗余

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

    3.1.什么是方法引用

    方法引用的分类

    3.2.静态方法引用

    静态方法引用类无需实例化,直接用类名去调用。

    1. public class Test01 {
    2. public static void main(String[] args) {
    3. Consumer c = Test01::sum;
    4. fun(c);
    5. }
    6. public static void fun(Consumer consumer){
    7. Integer[] arr={1,2,3,4,5};
    8. consumer.accept(arr);
    9. }
    10. public static void sum(Integer[] arr){
    11. int sum=0;
    12. for (int a:arr){
    13. sum+=a;
    14. }
    15. System.out.println("数组的和为:"+sum);
    16. }
    17. }

     3.3.实例方法引用

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

    1. public class Test {
    2. public static void main(String[] args) {
    3. People people = new People("张三",18);
    4. Supplier supplier = () -> {
    5. return people.getName();
    6. };
    7. fun(supplier);
    8. }
    9. public static void fun(Supplier supplier){
    10. String s = supplier.get();
    11. System.out.println("结果为:"+s);
    12. }
    13. }
    14. class People{
    15. private String name;
    16. private Integer age;
    17. @Override
    18. public String toString() {
    19. return "People{" +
    20. "name='" + name + '\'' +
    21. ", age=" + age +
    22. '}';
    23. }
    24. public People(String name, Integer age) {
    25. this.name = name;
    26. this.age = age;
    27. }
    28. public String getName() {
    29. return name;
    30. }
    31. public void setName(String name) {
    32. this.name = name;
    33. }
    34. public Integer getAge() {
    35. return age;
    36. }
    37. public void setAge(Integer age) {
    38. this.age = age;
    39. }
    40. }
  • 相关阅读:
    Qml中的那些坑(三)---MouseArea上的ListView滚轮事件穿透
    golang语言的gofly快速开发框架如何设置多样的主题说明
    Java并发编程—java多线程相关概念
    postman接口测试实战讲解
    FFmpeg常用实例详解
    真正“搞”懂HTTP协议05之What's HTTP?
    Linux篇13动静态库
    java毕业设计仓库管理系统mybatis+源码+调试部署+系统+数据库+lw
    Java泛型
    pytorch中torch.where()使用方法
  • 原文地址:https://blog.csdn.net/qq_44189274/article/details/125881221