• Java高级篇-----jdk1.8新特性


    1.Lambda表达式

    1.需求分析

    创建一个新的线程,指定线程要执行的任务

    1. package demo01;
    2. /**
    3. * @ProjectName: jdk1.8_1
    4. * @Package: demo01
    5. * @ClassName: Test01
    6. * @Author: 王振华
    7. * @Description:
    8. * @Date: 2022/7/19 19:03
    9. * @Version: 1.0
    10. */
    11. public class Test01 {
    12. public static void main(String[] args) {
    13. My my = new My();
    14. Thread t1 = new Thread(my);
    15. t1.start();
    16. //匿名内部类
    17. Runnable task = new Runnable() {
    18. @Override
    19. public void run() {
    20. System.out.println("这是使用匿名内部类方法时的任务对象");
    21. }
    22. };
    23. Thread t2 = new Thread(task);
    24. t2.start();
    25. }
    26. }
    27. class My implements Runnable{
    28. @Override
    29. public void run() {
    30. System.out.println("自定义任务接口类");
    31. }
    32. }

    代码分析: 


             * 1.Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心
             * 2.为了指定run方法体,不得不需要Runnable实现类
             * 3.为了省去定义一个Runnable的实现类,不得不使用匿名内部类
             * 4.必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错
             * 5.而实际上,我们只在乎方法体中的代码

    2.Lambda表达式初体验

    Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码

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

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

    Lambda表达式的优点:简化了匿名内部类的使用,语法更加简单
    匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。

    3.Lambda的语法规则

    概念:

    Lambda表达式:特殊的匿名内部类,语法更加简洁

    Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递

    语法:

    <函数式接口> <变量名> = (参数1,参数2...) -> {

            //方法体

    };

    格式说明:

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

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

    3.1.练习无参无返回值的Lambda表达式

    1. package demo02;
    2. /**
    3. * @ProjectName: jdk1.8_1
    4. * @Package: demo02
    5. * @ClassName: Test02
    6. * @Author: 王振华
    7. * @Description:
    8. * @Date: 2022/7/19 19:13
    9. * @Version: 1.0
    10. */
    11. //无参无返回值的Lambda表达式
    12. public class Test02 {
    13. public static void main(String[] args) {
    14. //匿名内部类
    15. /* Swimmable swimmable = new Swimmable() {
    16. @Override
    17. public void swimming(String name) {
    18. System.out.println("这是使用匿名内部类的方式");
    19. }
    20. };
    21. fun(swimmable);*/
    22. //lambda表达式
    23. fun(name -> {
    24. System.out.println("这是使用lambda表达式"+name);
    25. });
    26. }
    27. public static void fun(Swimmable s){
    28. s.swimming("郭富城");
    29. }
    30. }
    31. //函数式接口
    32. interface Swimmable{
    33. public void swimming(String name);
    34. }

    3.2.练习有参数且有返回值的Lambda表达式

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

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

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

    1. package demo02;
    2. import java.util.ArrayList;
    3. import java.util.Collections;
    4. import java.util.Comparator;
    5. import java.util.List;
    6. /**
    7. * @ProjectName: jdk1.8_1
    8. * @Package: demo02
    9. * @ClassName: Test03
    10. * @Author: 王振华
    11. * @Description:
    12. * @Date: 2022/7/19 19:26
    13. * @Version: 1.0
    14. */
    15. //有参有返回值的Lambda表达式
    16. public class Test03 {
    17. public static void main(String[] args) {
    18. List list = new ArrayList<>();
    19. list.add(new Person("张三",20,158));
    20. list.add(new Person("李四",12,178));
    21. list.add(new Person("王五",30,167));
    22. list.add(new Person("赵六",15,184));
    23. //对集合中的元素进行排序 按照年龄从大到小
    24. //Collections: 集合的工具类 //传统做法:Comparator: 排序规则接口
    25. Collections.sort(list, new Comparator() {
    26. //int: 0表示新加的元素和集合中原来的比对的相同
    27. // //1: o2比o1大
    28. // //-1: o2比o1小
    29. @Override
    30. public int compare(Person o1, Person o2) {
    31. return o1.getAge()-o2.getAge();
    32. }
    33. });
    34. for(Person person : list){
    35. System.out.println(person);
    36. }
    37. System.out.println("=================================================");
    38. //使用Lambda表达式 按年龄从小到大
    39. Collections.sort(list,(o1,o2)->{return o2.getAge()- o1.getAge();});
    40. for(Person person : list){
    41. System.out.println(person);
    42. }
    43. }
    44. }
    45. class Person{
    46. private String name;
    47. private int age;
    48. private int height;
    49. public Person() {
    50. }
    51. public Person(String name, int age, int height) {
    52. this.name = name;
    53. this.age = age;
    54. this.height = height;
    55. }
    56. @Override
    57. public String toString() {
    58. return "Person{" +
    59. "name='" + name + '\'' +
    60. ", age=" + age +
    61. ", height=" + height +
    62. '}';
    63. }
    64. public String getName() {
    65. return name;
    66. }
    67. public void setName(String name) {
    68. this.name = name;
    69. }
    70. public int getAge() {
    71. return age;
    72. }
    73. public void setAge(int age) {
    74. this.age = age;
    75. }
    76. public int getHeight() {
    77. return height;
    78. }
    79. public void setHeight(int height) {
    80. this.height = height;
    81. }
    82. }

    3.3.详细介绍Lambda表达式

     2.函数式接口

     内置函数式接口的由来

    1. package demo03;
    2. /**
    3. * @ProjectName: jdk1.8_1
    4. * @Package: demo03
    5. * @ClassName: Test03
    6. * @Author: 王振华
    7. * @Description:
    8. * @Date: 2022/7/19 19:43
    9. * @Version: 1.0
    10. */
    11. public class Test03 {
    12. public static void main(String[] args) {
    13. int[] arr = {2,2,3,4,56,8};
    14. fun((arr1)->{
    15. int sum = 0;
    16. for(int n : arr1){
    17. sum += n;
    18. }
    19. System.out.println("数组的和:"+sum);
    20. },arr);
    21. }
    22. public static void fun(Operater operater,int[] arr){
    23. operater.getSum(arr);
    24. }
    25. }
    26. @FunctionalInterface
    27. interface Operater{
    28. //求数组的和
    29. public abstract void getSum(int[] arr);
    30. }

    分析

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

    常见得函数式接口

    java.util.function保存

     2.1.Consumer消费型接口

    T:表示参数的泛型

    有参数,无返回值。

    1. package demo04;
    2. import java.util.function.Consumer;
    3. /**
    4. * @ProjectName: jdk1.8_1
    5. * @Package: demo04
    6. * @ClassName: Test01
    7. * @Author: 王振华
    8. * @Description: 消费型接口
    9. * @Date: 2022/7/19 19:50
    10. * @Version: 1.0
    11. */
    12. public class Test01 {
    13. public static void main(String[] args) {
    14. fun((t)->{
    15. System.out.println("花费了"+t+"元");
    16. },1000);
    17. }
    18. //调用某个方法时,该方法需要的参数为接口类型,这时就应该能想到Lambda
    19. public static void fun(Consumer consumer,double money){
    20. consumer.accept(money);
    21. }
    22. }

    2.2.Supperlier供给型接口

    T:表示返回结果的泛型

    无参数,有返回值

    1. package demo04;
    2. import java.util.Random;
    3. import java.util.function.Supplier;
    4. /**
    5. * @ProjectName: jdk1.8_1
    6. * @Package: demo04
    7. * @ClassName: Test02
    8. * @Author: 王振华
    9. * @Description: 供给型接口
    10. * @Date: 2022/7/19 19:56
    11. * @Version: 1.0
    12. */
    13. public class Test02 {
    14. public static void main(String[] args) {
    15. //0-9的随机整数
    16. fun(()->{return new Random().nextInt(10);
    17. });
    18. }
    19. public static void fun(Supplier supplier){
    20. Integer s = supplier.get();
    21. System.out.println(s);
    22. }
    23. }

    2.3.Function函数型接口

    T: 参数类型的泛型

    R: 函数返回结果的泛型

    有参数,有返回值。

    例子: 传入一个字符串把小写转换为大写。

    1. package demo04;
    2. import java.util.Locale;
    3. import java.util.function.Function;
    4. /**
    5. * @ProjectName: jdk1.8_1
    6. * @Package: demo04
    7. * @ClassName: Test03
    8. * @Author: 王振华
    9. * @Description: 函数型接口
    10. * @Date: 2022/7/19 20:01
    11. * @Version: 1.0
    12. */
    13. public class Test03 {
    14. public static void main(String[] args) {
    15. fun((t)->{
    16. //转成大写
    17. return t.toUpperCase();
    18. },"hello world");
    19. }
    20. public static void fun(Function function,String msg){
    21. String apply = function.apply(msg);
    22. System.out.println(apply);
    23. }
    24. }

    2.4.Predicate断言型接口

    T: 参数的泛型

    boolean test(T t);

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

    1. package demo04;
    2. import java.util.function.Predicate;
    3. /**
    4. * @ProjectName: jdk1.8_1
    5. * @Package: demo04
    6. * @ClassName: Test04
    7. * @Author: 王振华
    8. * @Description: 断言型接口
    9. * @Date: 2022/7/19 20:04
    10. * @Version: 1.0
    11. */
    12. public class Test04 {
    13. public static void main(String[] args) {
    14. //判断字符串的长度是否大于3,大于为true,否则相反
    15. fun((t)->{return t.length()>3;},"会当凌绝顶");
    16. }
    17. public static void fun(Predicate predicate,String msg){
    18. boolean test = predicate.test(msg);
    19. System.out.println(test);
    20. }
    21. }

     3.方法引用

    3.1.Lambda表达式的冗余

    1. package demo05;
    2. import java.util.function.Consumer;
    3. /**
    4. * @ProjectName: jdk1.8_1
    5. * @Package: demo05
    6. * @ClassName: Test01
    7. * @Author: 王振华
    8. * @Description: Lombda的冗余
    9. * @Date: 2022/7/19 20:14
    10. * @Version: 1.0
    11. */
    12. public class Test01 {
    13. public static void main(String[] args) {
    14. fun((t)->{
    15. String s1 = t.toUpperCase();
    16. System.out.println(s1);
    17. },"hello world");
    18. }
    19. public static void fun(Consumer consumer,String msg){
    20. consumer.accept(msg);
    21. }
    22. public static void toUpperCase(String s){
    23. String s1 = s.toUpperCase();
    24. System.out.println(s1);
    25. }
    26. }

    分析:

    我们发现toUpperCase方法和Consumer消费型接口中的代码体此时一致,我们重复写会使代码冗余。

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

    1. package demo05;
    2. import java.util.function.Consumer;
    3. /**
    4. * @ProjectName: jdk1.8_1
    5. * @Package: demo05
    6. * @ClassName: Test01
    7. * @Author: 王振华
    8. * @Description:
    9. * @Date: 2022/7/19 20:14
    10. * @Version: 1.0
    11. */
    12. public class Test01 {
    13. public static void main(String[] args) {
    14. fun((t)->Test01.toUpperCase(t),"hello world");
    15. fun(Test01::toUpperCase,"hello world"); //这两种 方法是一样的
    16. }
    17. public static void fun(Consumer consumer,String msg){
    18. consumer.accept(msg);
    19. }
    20. public static void toUpperCase(String s){
    21. String s1 = s.toUpperCase();
    22. System.out.println(s1);
    23. }
    24. }

    请注意其中的双冒号 :: 写法,这被称为“方法引用”,是一种新的语法。

    3.2.什么是方法引用

    方法引用的分类

     3.3.静态方法引用

    1. package demo06;
    2. import java.util.ArrayList;
    3. import java.util.Comparator;
    4. import java.util.List;
    5. /**
    6. * @ProjectName: jdk1.8_1
    7. * @Package: demo06
    8. * @ClassName: Test06
    9. * @Author: 王振华
    10. * @Description: 静态方法引用
    11. * @Date: 2022/7/19 21:23
    12. * @Version: 1.0
    13. */
    14. public class Test06 {
    15. public static void main(String[] args) {
    16. List list = new ArrayList<>();
    17. list.add(1);
    18. list.add(3);
    19. list.add(2);
    20. list.add(6);
    21. list.add(4);
    22. //Comparator comparator = ((o1, o2) -> o1-o2);
    23. //Comparator comparator = ((o1, o2) -> Integer.compare(o1,o2));
    24. //调用了Integer类的静态方法compare方法
    25. Comparator comparator = Integer::compare;
    26. list.sort(comparator);
    27. System.out.println(list);
    28. }
    29. }

    3.4.实例方法引用

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

    1. package demo07;
    2. import java.time.Period;
    3. import java.util.Arrays;
    4. import java.util.Comparator;
    5. import java.util.function.Supplier;
    6. /**
    7. * @ProjectName: jdk1.8_1
    8. * @Package: demo07
    9. * @ClassName: Test07
    10. * @Author: 王振华
    11. * @Description: 实例方法引用
    12. * @Date: 2022/7/19 21:31
    13. * @Version: 1.0
    14. */
    15. public class Test07 {
    16. public static void main(String[] args) {
    17. People[] peoples = {new People("张三",15),new People("李四",12),new People("王五",58),new People("赵六",20)};
    18. //该数组进行排序---年龄排序int compare(T o1, T o2);
    19. //Comparator comparator = (o1, o2) -> o1.getAge()-o2.getAge();
    20. //如果在lambda表达式中有且仅有一条语句,而且这条语句是对方法的调用。这时可以考虑使用方法引用
    21. //Comparator comparator = (o1,o2)-> People.compare(o1,o2);
    22. Comparator comparator = People::compare;
    23. Arrays.sort(peoples,comparator);
    24. System.out.println(Arrays.asList(peoples));
    25. People p=new People("李四",25);
    26. //在这个lambda表达式中只有一条语句,而且这条语句又是调用了某个方法
    27. //Supplier s=()-> p.getName();
    28. Supplier s=p::getName;
    29. fun(s);
    30. }
    31. public static void fun(Supplier supplier){
    32. String s = supplier.get();
    33. System.out.println("结果为:"+s);
    34. }
    35. }
    36. class People{
    37. private String name;
    38. private int age;
    39. public People(String name, int age) {
    40. this.name = name;
    41. this.age = age;
    42. }
    43. @Override
    44. public String toString() {
    45. return "People{" +
    46. "name='" + name + '\'' +
    47. ", age=" + age +
    48. '}';
    49. }
    50. public static int compare(People p1, People p2){
    51. return p1.getAge()-p2.getAge();
    52. }
    53. public String getName() {
    54. return name;
    55. }
    56. public void setName(String name) {
    57. this.name = name;
    58. }
    59. public int getAge() {
    60. return age;
    61. }
    62. public void setAge(int age) {
    63. this.age = age;
    64. }
    65. }

  • 相关阅读:
    MyBatis
    基于Redis实现消息队列的实践
    Swin Transformer、ViT作者等共话:好的基础模型是CV 研究者的朴素追求
    棱镜七彩受邀参加“数字政府建设暨数字安全技术研讨会”
    [算法沉淀记录] 排序算法 —— 希尔排序
    Undefined symbols for architecture arm64
    【腾讯云Cloud Studio实战训练营】戏说cloud studio
    Taro.navigateTo 使用URL传参数和目标页面参数获取
    ESD门禁闸机系统的功能说明
    解决 “ImportError: attempted relative import with no known parent package“ 问题
  • 原文地址:https://blog.csdn.net/weixin_68509156/article/details/125886024