一.Arrays

用来操作数组的一个工具类

在Java中,没有内置的"Arrays工具类",但有一个名为java.util.Arrays的类,它包含了一些用于操作数组的静态方法。这个类主要用于数组的排序、搜索和复制

toString(类型[] arr):打印数组中的内容

int[] arr={20,30,5,8,9};
//public static String toString (类型[] arr)
//返回数组中的内容
System.out.println(Arrays.toString(arr)); //[20, 30, 5, 8, 9]
copyOfRange (类型[], 起始索引, 结束索引):复制范围内的数组,范围是左闭右开
//public static int[] copyOfRange(类型[], 起始索引, 结束索引) 左闭右开
//拷贝指定范围的数组,并返回一个新的数组
int[] copyArray = Arrays.copyOfRange(arr, 1, 3);//拷贝下标为 1,2号元素,左闭右开
System.out.println(Arrays.toString(copyArray)); //[30, 5]
copyOf(类型[], int newLength):复制指定长度的数组
//public static copyOf(类型[], int newLength)复制指定长度的数组
//长度大于原数组,补齐0,小于则复制0下标开始的一部分元素
int[] copyArr = Arrays.copyOf(arr, 10);
System.out.println(Arrays.toString(copyArr));//[20, 30, 5, 8, 9, 0, 0, 0, 0, 0]
setAll(double[] arr, IntToDoubleFunction generator):将数组中的数据改为新数据又存进去;传入参数为要改变的数组,以及一个改变的匿名函数(怎么改变原数组的规则)
 double[] ar = {32.0,15.4,89.3,52.1};
//public static setAll(double[] arr, IntToDoubleFunction generator)
//将数组中的数据改为新数据又存进去
Arrays.setAll(ar, new IntToDoubleFunction() {
//更改原始数据的方法
@Override
public double applyAsDouble(int value) {
//value是传入数组的下标,一次取值,分别为0,1,2.....
return ar[value]*10; //将数组中的每个元素扩大 10 倍
}
});
System.out.println(Arrays.toString(ar)); //[320.0, 154.0, 893.0, 521.0]
sort (类型[] arr):对数组排序,默认升序
//public static void sort (类型[] arr)
//对数组排序,默认升序
Arrays.sort(ar);
System.out.println(Arrays.toString(ar)); //[154.0, 320.0, 521.0, 893.0]

二.对象排序

对数组的基本类型元素排序是很简单的事情,我们在初学编程语言就了解了一些排序算法,比如,冒泡,插入,选择,快速排序等算法,十大基础排序算法

简单是因为,基本数据类型的元素值单一,可以直接通过值的大小进行升序或者降序排序

而当待排序的元素是对象的时候,似乎就不那么简单了

主要是基于对象的比较有很多方式可以比较,如对象在堆空间的地址大小,对象之间的各个属性值大小,这些都是可以比较的方式,所以我们在为同一类对象进行排序的时候一定要制定对应比较规则

制定比较规则的方式有两种:

一.让对象类实现Comparable接口,重写ComparaTo方法,自己制定比较规则

二.使用Arrays类的sort方法,创建Comparator比较器接口的匿名内部类对象,再制定比较规则

实现Comparable接口

Comparable 接口是 Java 中的一个标准接口,用于定义对象之间的自然顺序。当一个类实现了 Comparable 接口后,就意味着这个类的对象可以根据某个指定的属性进行排序。

要实现 Comparable 接口,类需要实现 compareTo 方法。这个方法接受另一个对象作为参数,并返回一个整数值,表示当前对象与参数对象的大小关系。返回值的具体含义如下:

  • 如果返回值为负整数,则表示当前对象小于参数对象。
  • 如果返回值为零,则表示当前对象等于参数对象。
  • 如果返回值为正整数,则表示当前对象大于参数对象

实现Comparable接口,重写ComparaTo方法:

public class Student implements Comparable<Student>{
private String name;
private double grade;
private int age;
public Student(String name, double grade, int age) {
this.name = name;
this.grade = grade;
this.age = age;
}
@Override
public int compareTo(Student o) {
return 0;
}
}

Comparable接口有一个泛型需要传入,直接传入当前类或接口就好了

重写的CompareTo接口就需要了解的是它的执行过程:

再启动这个方法的时候,是一个对象调用此方法和另一个对象比较,调用者就是This对象,另一个比较对象就是Student o代表的

所以两两相比较,就是this 和 o 之间的比较,比较完了,下一组又会重新刷洗 this和o所代表的对象

比如:我们需要比较年龄,年龄小的对象在前面,年龄大的在后面,注意上面的返回值约定

重写的compareTo()方法:

 @Override
public int compareTo(Student o) {
//约定
//如果 this 大于 o 对象的属性值,则返回正整数
//如果 this 小于 o 对象的属性值,则返回负整数
//如果 this 等于 o 对象的属性值,则返回0
if(this.age>o.age){
return 1;
}else if (this.age<o.age){
return -1;
}
return 0;
}

测试类:

public static void main(String[] args) {
Student[] st=new Student[4];
st[0]=new Student("李华",65,18);
st[1]=new Student("王明",95,19);
st[2]=new Student("张静",35,16);
st[3]=new Student("李丹",85,21);
Arrays.sort(st);
System.out.println(Arrays.toString(st));
//[Student{name='张静', grade=35.0, age=16},
// Student{name='李华', grade=65.0, age=18},
// Student{name='王明', grade=95.0, age=19},
// Student{name='李丹', grade=85.0, age=21}]
}

Arrays类的sort方法,创建Comparator匿名内部类

Comparator 是 Java 中的一个接口,用于定义对象的比较逻辑。通过实现这个接口,我们可以自定义对象的排序方式。

compare(Object o1, Object o2): 这个方法用于比较两个对象。返回值与 Comparable 接口中的 compareTo 方法类似,表示 o1 和 o2 的大小关系。

它也需要遵守约定和上面compareTo方法的约定是一样的

  • 如果返回值为负整数,则表示当前对象小于参数对象。
  • 如果返回值为零,则表示当前对象等于参数对象。
  • 如果返回值为正整数,则表示当前对象大于参数对象
Arrays.sort(st, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return 0;
}
});

如上,compare方法的两两对象比较就是o1,o2互相比较,它的约定和上面的一样

重写 compare方法:按照成绩升序排序

//按照成绩排序
Arrays.sort(st, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.getGrade()>o2.getGrade()){
return 1;
}else if (o1.getGrade()<o2.getGrade()){
return -1;
}
return 0;
}
});

Main函数展示结果:

System.out.println(Arrays.toString(st));
//[Student{name='张静', grade=35.0, age=16},
// Student{name='李华', grade=65.0, age=18},
// Student{name='李丹', grade=85.0, age=21},
// Student{name='王明', grade=95.0, age=19}]

要想逆序也很简单,只需要把大于改小于,把小于改大于就好了:

//按照成绩排序
Arrays.sort(st, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.getGrade()<o2.getGrade()){
return 1;
}else if (o1.getGrade()>o2.getGrade()){
return -1;
}
return 0;
}
});

三.Lambda表达式

Lambda表达式是JDK8开始新增的一种语法形式;作用:用于简化匿名内部类的写法

格式:

(被重写方法的形参列表) - >{

方法体;

}

匿名内部类的写法:

抽象类

public class Animal {
public static void main(String[] args) {
//匿名内部类
Dog dog = new Dog() {
@Override
void eat() {
System.out.println("Dog eat~~");
}
};
}
}
//抽象类
abstract class Dog{
//抽象方法
abstract void eat();
}

接口类

public class Animal {
public static void main(String[] args) {
//匿名内部类
Cat cat = new Cat() {
@Override
public void eat() {
System.out.println("cat eat ~~");
}
};
}
}
//接口
interface Cat{
void eat();
}

今天我们要学习的Lambda表达式可以简化匿名内部类的写法,但是,需要注意的是不是所有的匿名内部类都可以简化写法

抽象类的匿名内部类是不能简化的

只能简化函数式接口方法的匿名内部类

简化Cat匿名内部类的写法:

public class Animal {
public static void main(String[] args) {
//Lambda表达式简化
Cat cat = () ->{
System.out.println("cat eat ~~");
};
}
}
//接口
interface Cat{
void eat();
}

什么是函数式接口呢?

有且仅有一个抽象方法的接口

同时如果我们看到一些接口上有@FunctionalInterface注解的接口就一定是函数式接口

@FunctionalInterface
interface Cat{
void eat();
}

此注解会抑制接口只能有一个抽象方法

重写Arrays.sort()方法

原方法体:

Student[] st=new Student[4];
st[0]=new Student("李华",65,18);
st[1]=new Student("王明",95.2,19);
st[2]=new Student("张静",35,16);
st[3]=new Student("李丹",95.1,21);
//按照成绩排序
Arrays.sort(st, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o1.getGrade(),o2.getGrade());
}
});
System.out.println(Arrays.toString(st));

我们可以看看Comparator接口是不是函数式接口:

有注解,妥妥的函数式接口,所以可以使用Lambda表达式进行加简化Arrays.sort()方法

Arrays.sort(st,(Student o1, Student o2) -> {
return Double.compare(o1.getGrade(),o2.getGrade());
});

上面的写法式最原始的Lambda表达式的写法,后面的Java开发又更新了很多新的简化规则,还能继续简化:

规则:

  1. 参数类型可以省略不写
  2. 只有一个参数时,括号()可以不写
  3. Lambda的主体方法中只有一句话时,可以省略大括号{ } 还有分号;如果这一行代码是return 语句,return 也可以不写

满足 1,2的接口:

public class Animal {
public static void main(String[] args) {
//Lambda表达式简化
Cat cat = vale ->{
System.out.println("cat eat ~~");
};
}
}
//接口
@FunctionalInterface
interface Cat{
void eat(int value);
}

满足1,3的接口:

//原Lambda
Arrays.sort(st,(Student o1, Student o2) -> {
return Double.compare(o1.getGrade(),o2.getGrade());
});
//继续简化
Arrays.sort(st,(o1, o2) -> Double.compare(o1.getGrade(),o2.getGrade()));

满足1,2,3的接口:

public class Animal {
public static void main(String[] args) {
//Lambda表达式简化
Cat cat = vale -> System.out.println("cat eat ~~");
}
}
//接口
@FunctionalInterface
interface Cat{
void eat(int value);
}

四.方法引用简化Lambda表达式

对于Lambda表达式我们知道,是用来简化函数式接口的匿名函数构造的

而方法引用可以进一步简化Lambda表达式

静态方法引用

类名::静态方法

如果某个Lambda表达式只是调用一个静态方法,并且前后参数一致,就可以使用静态方法的引用

原Lambda表达式:

public class StaticMethodUseDemo {
public static void main(String[] args) {
int[] arr={10,20,30,40,50};
ToArr ta = (array,number) -> {
return ctrlArray(array,number);//对数组元素加 10
};
int[] addArray = ta.ctrlArray(arr,10);
System.out.println(Arrays.toString(addArray)); //[20, 30, 40, 50, 60]
}
//对数据元素进行加减
public static int[] ctrlArray(int[] arr,int number){
int[] temp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
temp[i]=arr[i]+number;
}
return temp;
}
}
@FunctionalInterface
interface ToArr{
int[] ctrlArray(int[] arr,int number);
}

注意Lambda表达式部分,只调用了一个静态方法:

        ToArr ta = (array,number) -> {
return ctrlArray(array,number);//对数组元素加 10
};

它是满足方法引用的,因为它只调用了一个静态方法,且前后的参数形式都是一样的,所以还可以继续简化,类名::静态方法名

ToArr ta = StaticMethodUseDemo::ctrlArray;//对数组元素加 10

如上代码,以类名::方法名的方式和上面的Lambda表达式未简化的是一样的

实例方法的引用

对象名::实例方法

如果Lambda表达式中只调用一个实例方法,且前后参数形式一致,就可以使用实例方法的引用

原Lambda表达式:

public class StaticMethodUseDemo {
public static void main(String[] args) {
int[] arr={10,20,30,40,50};
methodClass methodClass = new methodClass();
ToArr ta = (array,number) ->{
return methodClass.ctrlArray(arr,number);
};
int[] addArray = ta.ctrlArray(arr,10);//对数组元素加 10
System.out.println(Arrays.toString(addArray)); //[20, 30, 40, 50, 60]
}
}
//方法类
class methodClass{
//对数据元素进行加减
//实例方法非静态
public int[] ctrlArray(int[] arr,int number){
int[] temp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
temp[i]=arr[i]+number;
}
return temp;
}
}
@FunctionalInterface
interface ToArr{
int[] ctrlArray(int[] arr,int number);
}

我们可以观察一下Lambda表达式的部分:

        methodClass methodClass = new methodClass();
ToArr ta = (array,number) ->{
return methodClass.ctrlArray(arr,number);
};

它只使用了一个实例方法,且参数前后都是一致的,所以可以使用方法引用简化Lambda表达式:

methodClass methodClass = new methodClass();
ToArr ta = methodClass::ctrlArray;

特定类型的方法引用

类型::方法

如果某个Lambda表达式只调用一个实例方法,且第一个参数作为方法的主调,后面的参数都作为该实例方法的入参,就可以使用特定类型的方法的引用

示例 (a,b,c) -> a.method(b,c ) 或者 (a,b) -> a . method(b)

原Lambda表达式:

public static void main(String[] args) {
String[] names = {"andy","Bob","Alice","jack","desk"};//按名字排序
//不区分大小写
Arrays.sort(names, (o1,o2)-> {
return o1.compareToIgnoreCase(o2); //此方法是String自带的,可以不区分字符大小写进行比较
});
System.out.println(Arrays.toString(names));
//[Alice, andy, Bob, desk, jack]
}

我们注意看Lambda表达式:

Arrays.sort(names, (o1,o2)-> {
return o1.compareToIgnoreCase(o2); //此方法是String自带的,可以不区分字符大小写进行比较
});

符合Lambda表达式只有一个实例方法,并且第一个参数为主调,后面的参数作为方法入参,可以继续简化:

Arrays.sort(names, String::compareToIgnoreCase); //此方法是String自带的,可以不区分字符大小写进行比较

构造器引用

类名::new

当某个Lambda表达式正在创建对象的时候,且前后参数一致,就可以使用构造器引用

开发中是使用的比较少,因为没有人会写一个函数式接口目的只是为了创建一个对象

public class StaticMethodUseDemo {
public static void main(String[] args) {
//创建一个methodClass对象
ToArr ta = () ->{
return new methodClass();
};
methodClass creat = ta.creat();
}
}
//方法类
class methodClass{ }
@FunctionalInterface
interface ToArr{
methodClass creat();
}

主要看Lambda表达式:

ToArr ta = () ->{
return new methodClass();
};

Lambda的主体是创建一个对象,且参数都一致(没有参数),所以可以使用方法引用继续优化:

ToArr ta = methodClass::new;

总结:

Lambda表达式是蒸滴C,能简化成这样,真是没谁了

JavaImprove--Lesson05--Arrays,对象排序,Lambda表达式,方法引用简化Lambda表达式的更多相关文章

  1. Effective Java 第三版——43.方法引用优于lambda表达式

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  2. 函数式接口 & lambda表达式 & 方法引用

    拉呱: 终于,学习jdk8的新特性了,初体验带给我的感觉真爽,代码精简的不行,可读性也很好,而且,spring5也是把jdk8的融入到血液里,总之一句话吧,说的打趣一点,学的时候自己难受,学完了写出来 ...

  3. List对象排序的通用方法

    转自 @author chenchuang import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Me ...

  4. 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

    作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-language- ...

  5. Java笔记——Java8特性之Lambda、方法引用和Streams

    Java8已经推出了好一段时间了,而掌握Java8的新特性也是必要的,如果要进行Spring开发,那么可以发现Spring的官网已经全部使用Java8来编写示例代码了,所以,不学就看不懂. 这里涉及三 ...

  6. [转]深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

    以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...

  7. Java8特性之Lambda、方法引用和Streams

    这里涉及三个重要特性: Lambda 方法引用 Streams ① Lambda 最早了解Lambda是在C#中,而从Java8开始,Lambda也成为了新的特性,而这个新的特性的目的,就是为了消除单 ...

  8. JavaSE22-Lambda表达式&方法引用

    1.Lambda表达式 1.1 Lambda表达式的标准格式 1 (形式参数) -> {代码块} 形式参数:如果有多个参数,参数之间用逗号隔开:如果没有参数,留空即可 ->:由英文中画线和 ...

  9. lambda与方法引用

    哈喽,大家好,我是指北君. 虽然目前Java最新版本都已经到16了,但是绝大部分公司目前用的Java版本都是8,想当初Java8问世后,其Lambda表达式与方法引用可是最亮眼的新特性,目前,这两个特 ...

  10. Java8特性之Lambda、方法引用以及Stream流

    Java 8 中的 Streams API 详解:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/ Java笔记——Jav ...

随机推荐

  1. Oracle 高可用 阅读笔记

    1   个人理解概述 1.1  Oracle dg Oracle Data Guard通过从主数据库传输redo data,然后将apply redo到备用数据库,自动维护每个备用数据库.DG分为3个 ...

  2. 2023-10-14:用go语言,给定 pushed 和 popped 两个序列,每个序列中的 值都不重复, 只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时, 返回

    2023-10-14:用go语言,给定 pushed 和 popped 两个序列,每个序列中的 值都不重复, 只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时, 返回 ...

  3. [MAUI]深入了解.NET MAUI Blazor与Vue的混合开发

    @ 目录 Vue在混合开发中的特点 创建MAUI项目 创建Vue应用 使用element-ui组件库 JavaScript和原生代码的交互 传递根组件参数 从设备调用Javascript代码 从Vue ...

  4. Net 高级调试之二:CLR和Windows加载器及应用程序域介绍

    一.简介 今天是 Net 高级调试的第二篇文章,第一篇文章记录了自己学习 Net 高级调试的第一步,认识一些调试工具,有了工具的倚仗,我们开始仗剑走天涯了,开始Net 高级调试正式的征程了.我先说一下 ...

  5. Chromium Command Buffer原理解析

    Command Buffer 是支撑 Chromium 多进程硬件加速渲染的核心技术之一.它基于 OpenGLES2.0 定义了一套序列化协议,这套协议规定了所有 OpenGLES2.0 命令的序列化 ...

  6. 自然数的拆分问题(lgP2404)

    dfs.又调了一个小时,窝果然菜 需要传递的变量分别为目前搜索的数字:目前所有选中数字的和:目前所选数字个数. 见注释. #include<bits/stdc++.h> using nam ...

  7. 慎用:git reset --hard

    丧心病狂的命令:git reset --hard commit ,我以后没弄懂这个命令之前,再也不碰它了,背后凉嗖嗖的,谁敢啊. 事情的原由是我本地git commit 的时候,发现文件多了,想删掉本 ...

  8. CSS必学:元素之间的空白与行内块的幽灵空白问题

    作者:WangMin 格言:努力做好自己喜欢的每一件事 CSDN原创文章 博客地址 WangMin 我们在开发的过程中,难免会出现一些难以预料的问题.那么其中,CSS空白现象就是非常常见的问题之一.虽 ...

  9. Typora + PicGo 快乐书写 Markdown 文档

    声明 以下提及的图床服务商跟本人无任何商业来往,你可以根据自己的需要选择其他更适合的服务商. 个人观点 这是一个服务付费的时代,相比于自己折腾.在价格适当,服务到位的情况下,我更倾向于选择商业服务.毕 ...

  10. UIPath变量和参数

    一. UIPath变量   变量(Variables),变量是所有编程语言中必不可少的部分.对于UIPath来说自然也是如此,其承载了我们RPA流程中数据传递的重要作用.对于接触过编程的开发者来说,变 ...