一.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. 前端设计模式:工厂模式(Factory)

    00.基础概念 工厂模式封装了对象的创建new(),将消费者(使用)和生产者(实现)解耦. 工厂是干什么的?工厂是生产标准规格的商品的地方,建好工厂,投入原料(参数),产出特定规格的产品.so,工厂模 ...

  2. Python比较字符串格式类型时间大小

    已知的格式是 06/24/2021 15:47:01.491 时间比较的思路是,把数据转换成时间戳比较: 第一步是把 06/24/2021 15:47:01.491 格式转换称 2021-06-24 ...

  3. Merge-Lrc 合并歌词的小工具

    Merge-Lrc 背景 音乐区有群友希望各种乱七八糟的歌词(lrc 格式居多,里面甚至还有翻译)可以整理成单一的文件,或者一个仅翻译的歌词可以和原文的歌词合并.于是就开发了这款工具.地址:https ...

  4. 算法学习笔记(3.1): ST算法

    ST表 在RMQ(区间最值)问题中,著名的ST算法就是倍增的产物.ST算法可以在 \(O(n \log n)\) 的时间复杂度能预处理后,以 \(O(1)\) 的复杂度在线回答区间 [l, r] 内的 ...

  5. CMD和AMD理解

    #AMD <br>1.AMD就是Asynchronous Module Definition,中文名是异步模块定义的意思.<br>2.AMD解决两个问题:解决依赖.异步加载&l ...

  6. ThreadPoolExecutor使用浅谈

    1. 基础介绍 ThreadPoolExecutor是Python标准库concurrent.futures模块中的一个类,用于实现线程池的功能. ThreadPoolExecutor模块相比于thr ...

  7. Office XXE攻击

    一.什么是Office XXE攻击 Office XXE攻击是xxe攻击的一种,由于.xlsx与.docx是基于xml文件存储内容的,后端在解析这些xml时自然也会存在xxe攻击的可能. 这里是.xl ...

  8. source insight 中添加指定类型文件

    以下为source insight 3.X版本的设置方法: source insight 中过滤某些格式的文件. 建立source insight工程后,先暂时不要急于添加文件. 打开options- ...

  9. Node.js精进(12)——ElasticSearch

    ElasticSearch(简称 ES)是一款基于 Lucene 的分布式.可扩展.RESTful 风格的全文检索和数据分析引擎,擅长实时处理 PB 级别的数据. 一.基本概念 1)Lucene Lu ...

  10. WPF应用开发之附件管理

    在我们之前的开发框架中,往往都是为了方便,对附件的管理都会进行一些简单的封装,目的是为了方便快速的使用,并达到统一界面的效果,本篇随笔介绍我们基于SqlSugar开发框架的WPF应用端,对于附件展示和 ...