Java:Arrays类、Lambda表达式、JDK新特性(方法引用) --黑马笔记

一、Arrays类

1.1 Arrays基本使用

Arrays是操作数组的工具类,它可以很方便的对数组中的元素进行遍历、拷贝、排序等操作。

下面我们用代码来演示一下:遍历、拷贝、排序等操作。需要用到的方法如下:

public class ArraysTest1 {public static void main(String[] args) {// 1、public static String toString(类型[] arr): 返回数组的内容int[] arr = {10, 20, 30, 40, 50, 60};System.out.println(Arrays.toString(arr));//[10, 20, 30, 40, 50, 60]// 2、public static 类型[] copyOfRange(类型[] arr, 起始索引, 结束索引) :拷贝数组(指定范围,包前不包后)int[] arr2 = Arrays.copyOfRange(arr, 1, 4);System.out.println(Arrays.toString(arr2));//[20, 30, 40]// 3、public static copyOf(类型[] arr, int newLength):拷贝数组,可以指定新数组的长度。int[] arr3 = Arrays.copyOf(arr, 10);System.out.println(Arrays.toString(arr3));//[10, 20, 30, 40, 50, 60, 0, 0, 0, 0]// 4、public static setAll(double[] array, IntToDoubleFunction generator):把数组中的原数据改为新数据又存进去。double[] prices = {99.8, 128, 100};//                  0     1    2// 把所有的价格都打八折,然后又存进去。Arrays.setAll(prices, new IntToDoubleFunction() {@Overridepublic double applyAsDouble(int value) {// value = 0  1  2return prices[value] * 0.8;}});System.out.println(Arrays.toString(prices));//[79.84, 102.4, 80.0]// 5、public static void sort(类型[] arr):对数组进行排序(默认是升序排序)Arrays.sort(prices);System.out.println(Arrays.toString(prices));//[79.84, 80.0, 102.4]}
}

1.2 Arrays操作对象数组

刚才我们使用Arrays操作数组时,数组中存储存储的元素是int类型、double类型,是可以直接排序的,而且默认是升序排列。

如果数组中存储的元素类型是自定义的对象,如何排序呢?接下来,我们就学习一下Arrays如何对对象数组进行排序。

首先我们要准备一个Student类,代码如下:

public class Student implements Comparable<Student>{private String name;private double height;private int age;public Student(String name, double height, int age) {this.name = name;this.height = height;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", height=" + height +", age=" + age +'}';}
}

如果再写一个测试类,往数组中存储4个学生对象。此时,运行代码你会发现是会报错的。

因为Arrays根本就不知道按照什么规则进行排序。为了让Arrays知道按照什么规则排序,我们有如下的两种办法。

排序方式1:让Student类实现Comparable接口,同时重写compareTo方法。Arrays的sort方法底层会根据compareTo方法的返回值是正数、负数、还是0来确定谁大、谁小、谁相等。

代码如下:

public class Student implements Comparable<Student>{private String name;private double height;private int age;//...get、set、空参数构造方法、有参数构造方法...自己补全// 指定比较规则// this  o@Overridepublic int compareTo(Student o) {// 约定1:认为左边对象 大于 右边对象 请您返回正整数// 约定2:认为左边对象 小于 右边对象 请您返回负整数// 约定3:认为左边对象 等于 右边对象 请您一定返回0/* if(this.age > o.age){return 1;}else if(this.age < o.age){return -1;}return 0;*///上面的if语句,也可以简化为下面的一行代码return this.age - o.age; // 按照年龄升序排列// return o.age - this.age; // 按照年龄降序排列}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", height=" + height +", age=" + age +'}';}
}

排序方式2:在调用Arrays.sort(数组,Comparator比较器);时,除了传递数组之外,传递一个Comparator比较器对象。Arrays的sort方法底层会根据Comparator比较器对象的compare方法方法的返回值是正数、负数、还是0来确定谁大、谁小、谁相等。

代码如下:

public class ArraysTest2 {public static void main(String[] args) {// 目标:掌握如何对数组中的对象进行排序。Student[] students = new Student[4];students[0] = new Student("蜘蛛精", 169.5, 23);students[1] = new Student("紫霞", 163.8, 26);students[2] = new Student("紫霞", 163.8, 26);students[3] = new Student("至尊宝", 167.5, 24);// 2、public static <T> void sort(T[] arr, Comparator<? super T> c)// 参数一:需要排序的数组// 参数二:Comparator比较器对象(用来制定对象的比较规则)Arrays.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 制定比较规则了:左边对象 o1   右边对象 o2// 约定1:认为左边对象 大于 右边对象 请您返回正整数// 约定2:认为左边对象 小于 右边对象 请您返回负整数// 约定3:认为左边对象 等于 右边对象 请您一定返回0
//                if(o1.getHeight() > o2.getHeight()){
//                    return 1;
//                }else if(o1.getHeight() < o2.getHeight()){
//                    return -1;
//                }
//                return 0; // 升序return Double.compare(o1.getHeight(), o2.getHeight()); // 升序// return Double.compare(o2.getHeight(), o1.getHeight()); // 降序}});System.out.println(Arrays.toString(students));}
}

二、Lambda表达式

我们学习一个JDK8新增的一种语法形式,叫做Lambda表达式。作用:用于简化匿名内部类代码的书写。

2.1 Lambda表达式基本使用

怎么去简化呢?Lamdba是有特有的格式的,按照下面的格式来编写Lamdba。

(被重写方法的形参列表) -> {
    被重写方法的方法体代码;
}

 要给说明一下的是,在使用Lambda表达式之前,必须先有一个接口,而且接口中只能有一个抽象方法。(注意:不能是抽象类,只能是接口)

像这样的接口,我们称之为函数式接口,只有基于函数式接口的匿名内部类才能被Lambda表达式简化。

public interface Swimming{void swim();
}

有了以上的Swimming接口之后,接下来才能再演示,使用Lambda表达式,简化匿名内部类书写。

public class LambdaTest1 {public static void main(String[] args) {// 目标:认识Lambda表达式.//1.创建一个Swimming接口的匿名内部类对象Swimming s = new Swimming(){@Overridepublic void swim() {System.out.println("学生快乐的游泳~~~~");}};s.swim();//2.使用Lambda表达式对Swimming接口的匿名内部类进行简化Swimming s1 = () -> {System.out.println("学生快乐的游泳~~~~");};s1.swim();}
}

好的,我们现在已经知道Lamdba表达式可以简化基于函数式接口的匿名内部类的书写。接下来,我们可以把刚才使用Arrays方法时的代码,使用Lambda表达式简化一下了。

public class LambdaTest2 {public static void main(String[] args) {// 目标:使用Lambda简化函数式接口。double[] prices = {99.8, 128, 100};//1.把所有元素*0.8: 先用匿名内部类写法Arrays.setAll(prices, new IntToDoubleFunction() {@Overridepublic double applyAsDouble(int value) {// value = 0  1  2return prices[value] * 0.8;}});//2.把所有元素*0.8: 改用Lamdba表达式写法Arrays.setAll(prices, (int value) -> {return prices[value] * 0.8;});System.out.println(Arrays.toString(prices));System.out.println("-----------------------------------------------");Student[] students = new Student[4];students[0] = new Student("蜘蛛精", 169.5, 23);students[1] = new Student("紫霞", 163.8, 26);students[2] = new Student("紫霞", 163.8, 26);students[3] = new Student("至尊宝", 167.5, 24);//3.对数组中的元素按照年龄升序排列: 先用匿名内部类写法Arrays.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.getHeight(), o2.getHeight()); // 升序}});//4.对数组中的元素按照年龄升序排列: 改用Lambda写法Arrays.sort(students, (Student o1, Student o2) -> {return Double.compare(o1.getHeight(), o2.getHeight()); // 升序});System.out.println(Arrays.toString(students));}
}

2.2 Lambda表达式省略规则

刚才我们学习了Lambda表达式的基本使用。Java觉得代码还不够简单,于是还提供了Lamdba表达式的几种简化写法。具体的简化规则如下:

1.Lambda的标准格式
    (参数类型1 参数名1, 参数类型2 参数名2)->{
        ...方法体的代码...
        return 返回值;
    }

2.在标准格式的基础上()中的参数类型可以直接省略
    (参数名1, 参数名2)->{
        ...方法体的代码...
        return 返回值;
    }
    
3.如果{}总的语句只有一条语句,则{}可以省略、return关键字、以及最后的“;”都可以省略
    (参数名1, 参数名2)-> 结果
    
4.如果()里面只有一个参数,则()可以省略
    参数名->结果

接下来从匿名内部类开始、到Lambda标准格式、再到Lambda简化格式,一步一步来简化一下。同学们体会一下简化的过程。

public class LambdaTest2 {public static void main(String[] args) {// 目标:使用Lambda简化函数式接口。double[] prices = {99.8, 128, 100};//1.对数组中的每一个元素*0.8: 匿名内部类写法Arrays.setAll(prices, new IntToDoubleFunction() {@Overridepublic double applyAsDouble(int value) {// value = 0  1  2return prices[value] * 0.8;}});//2.需求:对数组中的每一个元素*0.8,使用Lambda表达式标准写法Arrays.setAll(prices, (int value) -> {return prices[value] * 0.8;});//3.使用Lambda表达式简化格式1——省略参数类型Arrays.setAll(prices, (value) -> {return prices[value] * 0.8;});//4.使用Lambda表达式简化格式2——省略()Arrays.setAll(prices, value -> {return prices[value] * 0.8;});//5.使用Lambda表达式简化格式3——省略{}Arrays.setAll(prices, value -> prices[value] * 0.8 );System.out.println(Arrays.toString(prices));System.out.println("------------------------------------Student[] students = new Student[4];students[0] = new Student("蜘蛛精", 169.5, 23);students[1] = new Student("紫霞", 163.8, 26);students[2] = new Student("紫霞", 163.8, 26);students[3] = new Student("至尊宝", 167.5, 24);//1.使用匿名内部类Arrays.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.getHeight(), o2.getHeight()); // 升序}});//2.使用Lambda表达式表达式——标准格式Arrays.sort(students, (Student o1, Student o2) -> {return Double.compare(o1.getHeight(), o2.getHeight()); // 升序});//3.使用Lambda表达式表达式——省略参数类型Arrays.sort(students, ( o1,  o2) -> {return Double.compare(o1.getHeight(), o2.getHeight()); // 升序});//4.使用Lambda表达式表达式——省略{}Arrays.sort(students, ( o1,  o2) -> Double.compare(o1.getHeight(), o2.getHeight()));System.out.println(Arrays.toString(students));}
}

三、JDK8新特性(方法引用)

我们知道Lambda是用来简化匿名代码的书写格式的,而方法引用是用来进一步简化Lambda表达式的,它简化的更加过分。

3.1 静态方法引用

我们先学习静态方法的引用,还是用之前Arrays代码来做演示。现在准备好下面的代码:

public class Test1 {public static void main(String[] args) {Student[] students = new Student[4];students[0] = new Student("蜘蛛精", 169.5, 23);students[1] = new Student("紫霞", 163.8, 26);students[2] = new Student("紫霞", 163.8, 26);students[3] = new Student("至尊宝", 167.5, 24);// 原始写法:对数组中的学生对象,按照年龄升序排序Arrays.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge(); // 按照年龄升序排序}});// 使用Lambda简化后的形式Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());}
}

现在,我想要把下图中Lambda表达式的方法体,用一个静态方法代替:

准备另外一个类CompareByData类,用于封装Lambda表达式的方法体代码;

public class CompareByData {public static int compareByAge(Student o1, Student o2){return o1.getAge() - o2.getAge(); // 升序排序的规则}
}

现在我们就可以把Lambda表达式的方法体代码,改为下面的样子:

Arrays.sort(students, (o1, o2) -> CompareByData.compareByAge(o1, o2));

Java为了简化上面Lambda表达式的写法,利用方法引用可以改进为下面的样子。实际上就是用类名调用方法,但是把参数给省略了。这就是静态方法引用:

//静态方法引用:类名::方法名
Arrays.sort(students, CompareByData::compareByAge);

3.2 实例方法引用

还是基于上面的案例,我们现在来学习一下实例方法的引用。现在,我想要把下图中Lambda表达式的方法体,用一个实例方法代替。

在CompareByData类中,再添加一个实例方法,用于封装Lambda表达式的方法体。

接下来,我们把Lambda表达式的方法体,改用对象调用方法:

CompareByData compare = new CompareByData();
Arrays.sort(students, (o1, o2) -> compare.compareByAgeDesc(o1, o2)); // 降序

最后,再将Lambda表达式的方法体,直接改成方法引用写法。实际上就是用类名调用方法,但是省略的参数。这就是实例方法引用:

CompareByData compare = new CompareByData();
Arrays.sort(students, compare::compareByAgeDesc); // 降序

3.2 特定类型的方法引用

在学习之前还是需要给大家说明一下,这种特定类型的方法引用是没有什么道理的,只是语法的一种约定,遇到这种场景,就可以这样用。

Java约定:
    如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数作为方法的主调,后面的所有参数都是作为该实例方法的入参时,则就可以使用特定类型的方法引用。
格式:
    类型::方法名

 

public class Test2 {public static void main(String[] args) {String[] names = {"boby", "angela", "Andy" ,"dlei", "caocao", "Babo", "jack", "Cici"};// 要求忽略首字符大小写进行排序。Arrays.sort(names, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {// 制定比较规则。o1 = "Andy"  o2 = "angela"return o1.compareToIgnoreCase(o2);}});//lambda表达式写法Arrays.sort(names, ( o1,  o2) -> o1.compareToIgnoreCase(o2) );//特定类型的方法引用!Arrays.sort(names, String::compareToIgnoreCase);System.out.println(Arrays.toString(names));}
}

3.3 构造器引用

还是先说明一下,构造器引用在实际开发中应用的并不多,目前还没有找到构造器的应用场景。所以大家在学习的时候,也只是关注语法就可以了。

现在,我们准备一个JavaBean类,Car类:

public class Car {private String name;private double price;public Car() {}public Car(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "Car{" +"name='" + name + '\'' +", price=" + price +'}';}
}

因为方法引用是基于Lamdba表达式简化的,所以也要按照Lamdba表达式的使用前提来用,需要一个函数式接口,接口中代码的返回值类型是Car类型。

interface CreateCar{Car create(String name, double price);
}

最后,再准备一个测试类,在测试类中创建CreateCar接口的实现类对象,先用匿名内部类创建、再用Lambda表达式创建,最后改用方法引用创建。同学们只关注格式就可以,不要去想为什么(语法就是这么设计的)。

public class Test3 {public static void main(String[] args) {// 1、创建这个接口的匿名内部类对象。CreateCar cc1 = new CreateCar(){@Overridepublic Car create(String name, double price) {return new Car(name, price);}};//2、使用匿名内部类改进CreateCar cc2 = (name,  price) -> new Car(name, price);//3、使用方法引用改进:构造器引用CreateCar cc3 = Car::new;//注意:以上是创建CreateCar接口实现类对象的几种形式而已,语法一步一步简化。//4、对象调用方法Car car = cc3.create("奔驰", 49.9);System.out.println(car);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/464437.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

036 冒泡排序

代码实践 // 冒泡排序 static void bubbleSort(Comparable[] elements) {// 临时容器&#xff0c;用于变量交换值时存储Object temp;// 标志位 用于减少无意义的循环次数boolean flag;for (int i 0; i < elements.length - 1; i) {flag false;for (int j 0; j < elem…

低代码开发的数字化革新:实业界的成功秘诀与实践之路

在信息时代&#xff0c;实业界正迎来一场变革的风暴&#xff0c;传统的管理系统逐渐不再满足越来越复杂的生产流程和不断增长的市场需求&#xff0c;而低代码开发正如一颗璀璨的明星&#xff0c;将为企业带来前所未有的灵活性和创新力&#xff0c;这并非一场技术的简单变迁&…

洗地机买什么品牌好?最好的洗地机品牌

对于双职工家庭来说&#xff0c;日常家务活是一个很大的难题。所以就要借助洗地机来提升生活质量&#xff0c;确实智能家电能够帮助日常家务减负。市面上的洗地机的品牌是真的很多&#xff0c;笔者今天带大家一起来看看什么洗地机品牌好用。 该如何挑选适合自己的家用洗地机 …

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之AlphabetIndexer组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之AlphabetIndexer组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、AlphabetIndexer组件 可以与容器组件联动用于按逻辑结构快速定位容器显…

【EAI 013】BC-Z: Zero-Shot Task Generalization with Robotic Imitation Learning

论文标题&#xff1a;BC-Z: Zero-Shot Task Generalization with Robotic Imitation Learning 论文作者&#xff1a;Eric Jang, Alex Irpan, Mohi Khansari, Daniel Kappler, Frederik Ebert, Corey Lynch, Sergey Levine, Chelsea Finn 论文原文&#xff1a;https://arxiv.org…

ChatGpt报错:We ran into an issue while authenticating you解决办法

在登录ChatGpt时报错&#xff1a;Oops&#xff01;,We ran into an issue while authenticating you.(我们在验证您时遇到问题)&#xff0c;记录一下解决过程。 完整报错&#xff1a; We ran into an issue while authenticating you. If this issue persists, please contact…

ftp 指令连接服务器没反应怎么办?

当我们使用FTP指令连接服务器时&#xff0c;有时可能会遇到没有反应的情况。这可能是由多种原因引起的&#xff0c;下面我们将探讨一些常见的解决方法。 1、检查FTP服务器的地址和端口是否正确 确保您输入的服务器地址和端口号与FTP服务器的实际设置相匹配。如果地址或端口错误…

微信小程序(四十一)wechat-http的使用

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序&#xff08;二十&#xff09;Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 npm co…

2024-02-11 Unity 编辑器开发之编辑器拓展2 —— 自定义窗口

文章目录 1 创建窗口类2 显示窗口3 窗口事件回调函数4 窗口中常用的生命周期函数5 编辑器窗口类中的常用成员6 小结 1 创建窗口类 ​ 当想为 Unity 拓展一个自定义窗口时&#xff0c;只需实现继承 EditorWindow 的类即可&#xff0c;并在该类的 OnGUI 函数中编写面板控件相关的…

【数据结构】双向链表(链表实现+测试+原码)

前言 在双向链表之前&#xff0c;如果需要查看单链表来复习一下&#xff0c;链接在这里&#xff1a; http://t.csdnimg.cn/Ib5qS 1.双向链表 1.1 链表的分类 实际中链表的结构非常多样&#xff0c;以下情况组合起来就有8种链表结构&#xff1a; 1.1.1 单向或者双向 1.1.2 …

Redis集群模型

主从 全量同步 增量同步 哨兵 分片集群

选择影视行业创业的原因,影视从业者创业成功的秘密

一、教程描述 本套教程是面向影视从业者的创业教程&#xff0c;主讲人将把自己的创业经验、行业观察、成长心得分享给大家。如果你正在创业&#xff0c;这门课可以让你飞速成长、弯道超车。主讲人积累的行业经验&#xff0c;会让你比大多数同行站的更高&#xff0c;看的更宽。…