• JDK1.8新特性


    目录

    1.Lambda表达式

    1.1 概念

    1.2 语法

    1.3 代码分析

    1.3.1 无参无返回值

    1.3.2 有参有返回值

    1.3.3 lambda表达式注意事项

    2.函数式接口

    2.1 内置函数式接口

    2.2 Consumer

    2.3 Supplier供给型函数式接口

    2.4 Function 函数型函数式接口,r>

    2.5 Predicated

    3.方法引用

    3.1 什么是方法引用

    3.2 对象::实例方法

    3.3 类名::静态方法

    3.4 类名::实例方法

    3.5 类名::new 引用类的构造器

    3.6 类型[]::new


    1.Lambda表达式

    1.1 概念

    (1)Lambda表达式:特殊的匿名内部类,语法更简洁。

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

    1.2 语法

    基本语法

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

                                    //方法体

            };

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

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

    ->: 分隔符

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

    1.3 代码分析

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

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

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

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

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

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

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

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

    总代码展示:

    1. public class LambdaTest {
    2. public static void main(String[] args) {
    3. My m=new My();
    4. Thread t1=new Thread(m);
    5. t1.start();
    6. Thread t2=new Thread(new Runnable() {
    7. @Override
    8. public void run() {
    9. System.out.println("匿名函数式");
    10. }
    11. });
    12. t2.start();
    13. Runnable t3=()->{
    14. System.out.println("lambda表达式");
    15. };
    16. Thread t03=new Thread(t3);
    17. t03.start();
    18. Thread t4=new Thread(()->{
    19. System.out.println("lambda精简表达式");
    20. });
    21. t4.start();
    22. }
    23. }
    24. class My implements Runnable{
    25. @Override
    26. public void run() {
    27. System.out.println("Runnable方法");
    28. }
    29. }

    1.3.1 无参无返回值

    代码展示:

    1. public class WuCanWuFan {
    2. public static void main(String[] args) {
    3. Swimming swimming=new Swimming() {
    4. @Override
    5. public void swim() {
    6. System.out.println("小明在游泳");
    7. }
    8. };
    9. fun(swimming);
    10. System.out.println("================lambda=========================");
    11. // Swimming swimming1=()->{
    12. // System.out.println("小花在游泳");
    13. // };
    14. fun(()->{
    15. System.out.println("小花在游泳");
    16. });
    17. }
    18. public static void fun(Swimming swimming){
    19. swimming.swim();
    20. }
    21. }
    22. interface Swimming{
    23. public void swim();
    24. }

    1.3.2 有参有返回值

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

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

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

    代码展示:

    1. public class Compable {
    2. public static void main(String[] args) {
    3. List people=new ArrayList<>();
    4. people.add(new Person("张三",15,185));
    5. people.add(new Person("李四",23,179));
    6. people.add(new Person("王五",8,145));
    7. people.add(new Person("赵六",34,180));
    8. //对集合中的元素进行排序 按照年龄从小到大
    9. //传统做法:Comparator:排序规则接口
    10. Comparator comparator=new Comparator() {
    11. //int : 0表示新加的元素和集合中的元素是相等的
    12. //1表示新加的元素比集合中的元素大
    13. //-1表示新加的元素比集合中的元素小
    14. @Override
    15. public int compare(Person o1, Person o2) {
    16. return o2.getAge()- o1.getAge();
    17. }
    18. };
    19. Collections.sort(people,comparator);
    20. for (Person p:people) {
    21. System.out.println(p);
    22. }
    23. System.out.println("===============================lambda===============================");
    24. Comparator comparator1=(Person o1,Person o2)->{
    25. return o1.getAge()- o2.getAge();
    26. };
    27. Collections.sort(people,comparator1);
    28. for (Person p:people) {
    29. System.out.println(p);
    30. }
    31. }
    32. }
    33. class Person{
    34. private String name;
    35. private Integer age;
    36. private Integer tall;
    37. public Person() {
    38. }
    39. public Person(String name, Integer age, Integer tall) {
    40. this.name = name;
    41. this.age = age;
    42. this.tall = tall;
    43. }
    44. public String getName() {
    45. return name;
    46. }
    47. public void setName(String name) {
    48. this.name = name;
    49. }
    50. public Integer getAge() {
    51. return age;
    52. }
    53. public void setAge(Integer age) {
    54. this.age = age;
    55. }
    56. public Integer getTall() {
    57. return tall;
    58. }
    59. public void setTall(Integer tall) {
    60. this.tall = tall;
    61. }
    62. @Override
    63. public String toString() {
    64. return "Person{" +
    65. "name='" + name + '\'' +
    66. ", age=" + age +
    67. ", tall=" + tall +
    68. '}';
    69. }
    70. }

    1.3.3 lambda表达式注意事项

    注意事项 :

            形参列表的数据类型会自动推断

            如果形参列表为空,只需保留()

            若形参只有一个,()可以省略,只需要参数的名称即可(此题证明)

            如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则想省去{},则必须同时省略return,且执行语句也保证只有一句

            Lambda不会生成一个单独的内部类文件

    1. public class NoticeTest {
    2. public static void main(String[] args) {
    3. fun(n->{
    4. System.out.println(n+"正在玩手机");
    5. });
    6. }
    7. public static void fun(Plays plays){
    8. plays.play("小明");
    9. }
    10. }
    11. interface Plays{
    12. public void play(String name);
    13. }

    2.函数式接口

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

            常见的函数式接口:java.util.function保存

    2.1 内置函数式接口

            如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambdda表达式会被匹配到这个抽象方法上。

            @Functionallnterface注解检测接口是否符合函数式接口。

    1. public class Test03 {
    2. public static void main(String[] args) {
    3. Operater o=arr -> {
    4. int sum=0;
    5. for(int n:arr){
    6. sum+=n;
    7. }
    8. System.out.println("数组的和为:"+sum);
    9. };
    10. fun(o);
    11. }
    12. public static void fun(Operater operater){
    13. int[] arr={2,3,4,5,6,7,11};
    14. operater.getSum(arr);
    15. }
    16. }
    17. @FunctionalInterface
    18. interface Operater{
    19. //求数组的和
    20. public abstract void getSum(int[] arr);
    21. }

    2.2 Consumer

    消费型函数 :有参无返回值

    举例:去美甲店消费一次的开销

    1. public class ConsumerTest {
    2. public static void main(String[] args) {
    3. Consumer consumer=t->{
    4. System.out.println("美甲花了:"+t);
    5. };
    6. fun(consumer,200);
    7. }
    8. //调用某个方法时,该方法需要的参数为接口类型,这时就应该能想到使用lambda
    9. public static void fun(Consumer consumer, double money){
    10. consumer.accept(money);
    11. }
    12. }

    举例:遍历数组和

    1. public class ConsumerTest02 {
    2. public static void main(String[] args) {
    3. getSum(t->{
    4. int sum=0;
    5. for (int i:t) {//此处遍历t即代表arr
    6. sum+=i;
    7. }
    8. System.out.println(sum);
    9. },new int[]{1,2,3,4,5});
    10. }
    11. public static void getSum(Consumer<int[]> consumer, int[] arr){//注意Consumer
    12. consumer.accept(arr);
    13. }
    14. }

    2.3 Supplier供给型函数式接口

    T表示返回结果的泛型 :无参有返回值的函数式接口

    举例:随机获取0到10之间的数字

    1. public class SupplierTest {
    2. public static void main(String[] args) {
    3. getNumber(()->{
    4. return new Random().nextInt(10);
    5. });
    6. }
    7. public static void getNumber(Supplier supplier){
    8. Integer integer = supplier.get();
    9. System.out.println("获取数字为:"+integer);
    10. }
    11. }

    2.4 Function 函数型函数式接口

    有参,有返回值

    T:参数类型的泛型

    R:函数返回结果的泛型

    举例:将字符串转大写

    1. public class FunctionTest {
    2. public static void main(String[] args) {
    3. getUpper(t->{
    4. return t.toUpperCase(Locale.ROOT);//所传参数随便写
    5. },"hello world");
    6. }
    7. public static void getUpper(Function function,String str){
    8. String apply = function.apply(str);
    9. System.out.println("结果为:·"+apply);
    10. }
    11. }

    举例:计算字符串长度

    1. public class FunctionTest02 {
    2. public static void main(String[] args) {
    3. getLength(t->{
    4. return t.replace(" ","").length();
    5. },"hello world");
    6. }
    7. public static void getLength(Function function,String str){
    8. Integer apply = function.apply(str);
    9. System.out.println("长度为:"+apply);
    10. }
    11. }

    2.5 Predicated

    boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型

    举例:判断名字是否过长

    1. public class PredicateTest {
    2. public static void main(String[] args) {
    3. getNameLength(t->{
    4. return t.length()>3?true:false;
    5. },"迪丽热巴.迪力木拉提");
    6. }
    7. public static void getNameLength(Predicate predicate,String name){
    8. boolean test = predicate.test(name);
    9. System.out.println("名字长度是否超过3:"+test);
    10. }
    11. }

    3.方法引用

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

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

    举例:计算数组和

    1. public class PullIn {
    2. public static void getSum(int[] arr){
    3. int sum=0;
    4. for (Integer i:arr) {
    5. sum+=i;
    6. }
    7. System.out.println("数组和为:"+sum);
    8. }
    9. public static void sum(Consumer<int[]> consumer){
    10. int[] arr={1, 2, 3, 4, 5};
    11. consumer.accept(arr);
    12. }
    13. public static void main(String[] args) {
    14. //此处与上述getSum方法一模一样,造成冗余
    15. // sum(arr->{
    16. // int sum=0;
    17. // for (Integer i:arr) {
    18. // sum+=i;
    19. // }
    20. // System.out.println("数组和为:"+sum);
    21. // },new int[]{1, 2, 3, 4, 5});
    22. sum(PullIn::getSum);
    23. }
    24. }

    3.1 什么是方法引用

            方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体只是调用一个特定的已经存在的方法,则可以使用方法引用。

            常见形式:

            (1)对象::方法名

            (2)类名::静态方法

            (3)类名::普通方法

            (4)类名::new 调用的构造器

            (5)String[]::new 调用数组的构造器

    3.2 对象::实例方法

    注意:

    1.被引用的方法,参数要和接口中的抽象方法的参数一样

    2.当接口抽象方法有返回值时,被引用的方法也必须有返回值

    举例:获取当前时间

    1. public class PullInTest01 {
    2. //对象::实例方法
    3. public static void main(String[] args) {
    4. Date d=new Date();
    5. // Supplier time=()->{
    6. // return d.getTime();
    7. // };
    8. //使用方法引用
    9. Supplier time=d::getTime;
    10. //注意:
    11. //1.被引用的方法,参数要和接口中的抽象方法的参数一样
    12. //2.当接口抽象方法有返回值时,被引用的方法也必须有返回值
    13. Long aLong = time.get();
    14. System.out.println("aLong = "+aLong);
    15. }
    16. }

    3.3 类名::静态方法

    举例:获取当前时间

    1. public class PullInTest02 {
    2. //类名::静态方法
    3. public static void main(String[] args) {
    4. // Supplier su=()->{
    5. // return System.currentTimeMillis();
    6. // };
    7. Supplier su=System::currentTimeMillis;
    8. Long aLong = su.get();
    9. System.out.println("aLong="+aLong);
    10. }
    11. }

    3.4 类名::实例方法

    (注意:类名::实例方法实际上会将第一个参数作为方法的调用者)

    举例:字符串长度及截取字符串

    1. public class PullInTest03 {
    2. public static void main(String[] args) {
    3. //类名::实例方法(注意:类名::实例方法实际上会将第一个参数作为方法的调用者)
    4. // Function f1=(String str)->{
    5. // return str.length();
    6. // };
    7. Function f1=String::length;
    8. Integer hello = f1.apply("hello");
    9. System.out.println("字符串长度为:"+hello);
    10. //BiFunction f2=String::substring;
    11. //相当于这样的Lambda
    12. BiFunction f2=(String str,Integer index)->{
    13. return str.substring(index);
    14. };
    15. String helloworld = f2.apply("helloworld", 3);
    16. System.out.println(helloworld);
    17. }
    18. }

    3.5 类名::new 引用类的构造器

    举例:person介绍

    Person类

    1. public class Person {
    2. private String name;
    3. private Integer age;
    4. public Person() {
    5. System.out.println("调用无参构造");
    6. }
    7. public Person(String name, Integer age) {
    8. System.out.println("调用有参构造"+name+"---"+age);
    9. this.name = name;
    10. this.age = age;
    11. }
    12. @Override
    13. public String toString() {
    14. return "Person{" +
    15. "name='" + name + '\'' +
    16. ", age=" + age +
    17. '}';
    18. }
    19. public String getName() {
    20. return name;
    21. }
    22. public void setName(String name) {
    23. this.name = name;
    24. }
    25. public Integer getAge() {
    26. return age;
    27. }
    28. public void setAge(Integer age) {
    29. this.age = age;
    30. }
    31. }

    测试类

    1. public class PullTest04 {
    2. //类名::new 引用类的构造器
    3. public static void main(String[] args) {
    4. // Supplier su=()->{
    5. // return new Person();
    6. // };
    7. Supplier su=Person::new;
    8. Person person = su.get();
    9. System.out.println(person);
    10. // BiFunction bif=(String name,Integer age)->{
    11. // return new Person(name,age);
    12. // };
    13. BiFunction bif=Person::new;
    14. Person name = bif.apply("小明", 18);
    15. System.out.println(name);
    16. }
    17. }

    3.6 类型[]::new

    举例:数组存放

    1. public class PullInTest05 {
    2. //类型【】::new
    3. public static void main(String[] args) {
    4. // Function f1=(Integer length)->{
    5. // return new int[length];
    6. // };
    7. Functionint[]> f1=int[]::new;
    8. int[] apply = f1.apply(10);
    9. System.out.println(Arrays.toString(apply));
    10. }
    11. }

  • 相关阅读:
    Linux上的Redis客户端软件G-dis3
    .Net服务器性能监控,应用耗时统一监控平台
    Kubernetes etcd备份恢复
    [Linux] Network: IPv6 link-local 地址是否可用不自动生成
    leetCode 647.回文子串 动态规划 + 优化空间 / 中心扩展法 + 双指针
    云原生下GIS服务规划与设计
    记录一次内存泄漏导致页面崩溃的排查过程
    04 RocketMQ - Producer 源码分析
    Leetcode 284. Peeking Iterator (Iterator设计题)
    (matplotlib)如何让各个子图ax大小(宽度和高度)相等
  • 原文地址:https://blog.csdn.net/qq_50896786/article/details/125881847