一.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. Python网络编程——操作系统基础、网络通信原理、.网络通信实现、DNS域名解析、 网络通信流程

    文章目录 一.操作系统基础 二.网络通信原理 2.1 互联网的本质就是一系列的网络协议 2.2 osi七层协议 2.3 tcp/ip五层模型讲解 2.3.1 物理层 2.3.2 数据链路层 2.3.3 ...

  2. Go 常用命令介绍

    Go 常用命令 目录 Go 常用命令 一.Go 常用命令 1.1 go build 1.1.1 指定输出目录 1.1.2 常用环境变量设置编译操作系统和 CPU 架构 1.1.3 查看支持的操作系统和 ...

  3. linux常用命令(七)

    用于系统内信息交流的相关命令 echo mesg wall write echo:在显示器上显示文字 命令语法:echo[选项] [字符串] 选项 选项含义 -n 表示输出文字后不换行 例子:将文本& ...

  4. PolarD&N2023秋季个人挑战—Crypto全解

    EasyRSA (额..这个题看错了不是挑战赛的.这里当做好题记录下来了) 题目信息:500 分 5 Polar币 from Crypto.Util.number import bytes_to_lo ...

  5. SpringBoot如何缓存方法返回值?

    目录 Why? HowDo annotation MethodCache MethodCacheAspect controller SpringCache EnableCaching Cacheabl ...

  6. 虹科干货 | 虹科Redis企业版数据库的延迟如此之小,proxy功不可没!

    在Redis企业版集群的后台发生了许多事件,proxy(代理)隐藏了数据库客户端的所有活动. 大多数开发人员在构建应用程序时都会从小规模开始,使用简单的Redis开源(Redis OSS)数据库.在初 ...

  7. HTML-9

    (一)常用方法 toFixed(); 四舍五入到小数点后几位 var x=9.656; x.toFixed(0);//10 x.toFixed(2);//9.66 x.toFixed(4);//9.6 ...

  8. 记录一下我的ctf比赛的web题目

    Web之getshell: 具体代码如下 <?php highlight_file(__FILE__); error_reporting(0); echo "<h1>WEL ...

  9. JVM核心知识体系(转)

    1.问题 1.如何理解类文件结构布局? 2.如何应用类加载器的工作原理进行将应用辗转腾挪? 3.热部署与热替换有何区别,如何隔离类冲突? 4.JVM如何管理内存,有何内存淘汰机制? 5.JVM执行引擎 ...

  10. MacOS X终端里SSH会话管理

    http://codelife.me/blog/2012/09/01/ssh-session-profile-management-in-terminal-of-macos-x/ 本文介绍如何在终端里 ...