news 2025/12/24 19:02:03

【JavaSE】十三、枚举类Enum Lambda表达式 列表排序常见写法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【JavaSE】十三、枚举类Enum Lambda表达式 列表排序常见写法

文章目录

  • Ⅰ. 枚举类定义与使用
  • Ⅱ. 枚举类的构造方法默认就是 `private`
  • 总结
  • Ⅲ. 什么是 `Lambda` 表达式
  • Ⅳ. `Lambda` 表达式的使用
  • 列表排序的常用写法
    • 1. **基本比较(数值)**
      • `Integer.compare(a, b)`
    • 2. **方法引用 +** **`Comparator.comparing`**
    • 3. **多条件排序**
    • 4. **倒序排序**
    • 5. **处理 null 值**
    • 6. **字符串比较(忽略大小写)**
    • 7. **完全自定义规则**

Ⅰ. 枚举类定义与使用

publicenumColor{RED,GREEN,BLUE,YELLOW,ORANGE,PURPLE,PINK,BROWN,BLACK,WHITE;}

每个我们写的enum类都会默认继承于一个抽象类Enum,如下图所示:

而这个Enum抽象类中有挺多方法,如下所示:

下面是使用举例:

publicstaticvoidmain(String[]args){// 使用Color.RED直接访问枚举元素,或者直接RED都行,但不能使用new来生成枚举类对象Colorcolor=Color.RED;System.out.println(color.name());// 输出颜色名称System.out.println(color.ordinal());// 输出颜色的序号System.out.println(color);// 直接输出颜色对象System.out.println(color.describeConstable());// 输出颜色的描述信息System.out.println(Color.valueOf("BLACK"));// 通过名称获取枚举值// 有个比较特殊的是values()方法,它可以返回所有枚举值数组,它不存在Enum中,而是在编译时由编译器生成的。// 但是如果枚举值太多,可能导致内存溢出,所以一般不用这个方法。System.out.println("----------------------输出所有枚举元素:");Color[]colors=Color.values();for(inti=0;i<colors.length;++i){System.out.println(colors[i]+" "+colors[i].ordinal());}Colorc2=newColor();// ❌不能实例化枚举类,只能通过枚举值访问其属性和方法。}// 运行结果:RED0REDOptional[EnumDesc[Color.RED]]BLACK----------------------输出所有枚举元素: RED0GREEN1BLUE2YELLOW3ORANGE4PURPLE5PINK6BROWN7BLACK8WHITE9

这里要注意values()是由Java编译器为每个枚举类自动生成的静态方法,所以在Enum类里是找不到它的源码的,但每个具体的枚举类都有它。

还有就是枚举类内也可以有方法,并且这些方法只能通过枚举元素来调用,而不能直接通过枚举类名来调用,如下图所示:

Ⅱ. 枚举类的构造方法默认就是private

枚举类的构造方法是隐式private的,是为了:

  • 保证枚举常量的唯一性
  • 避免外部创建新的实例(防止破坏enum的封闭性)
  • 在某些场景下,天然实现单例模式,并且是线程安全的、防反射、防反序列化

首先枚举类也是可以写构造函数,然后枚举元素可以进行构造,如下所示:

publicenumColor{RED("red",1),GREEN("green",2),BLUE("blue",3);privateStringname;privateintvalue;// 构造函数默认就是private,不写也可以,但是不能写其它的访问权限privateColor(Stringname,intvalue){this.name=name;this.value=value;}publicstaticvoidmain(String[]args){Colorc=Color.RED;System.out.println(c.name);System.out.println(c.value);}}// 运行结果:red1

然后测试一下不同对象引用同一个枚举元素,是不是同一地址:

publicstaticvoidmain(String[]args){Colorc1=Color.RED;Colorc2=Color.RED;System.out.println(c1==c2);// true}

很明显不同对象引用同一个枚举元素,都是同一个对象

然后看一下是不是能够在类内调用构造方法:

publicstaticvoidmain(String[]args){Colorc=newColor();// ❌报错:无法实例化枚举类型}

那么就想,能不能用反射来设置访问权限,强制调用构造方法,如下所示:

publicstaticvoidmain(String[]args){try{// 先获取构造函数,再设置Accessible为trueClass<?>cs=Class.forName("EnumDemo.Color");Constructor<?>ctor=cs.getDeclaredConstructor(String.class,int.class);ctor.setAccessible(true);// 调用构造函数创建对象Colorc=(Color)ctor.newInstance("yellow",4);System.out.println(c.name+" "+c.value);}catch(ClassNotFoundExceptione){thrownewRuntimeException(e);}catch(InvocationTargetExceptione){thrownewRuntimeException(e);}catch(NoSuchMethodExceptione){thrownewRuntimeException(e);}catch(InstantiationExceptione){thrownewRuntimeException(e);}catch(IllegalAccessExceptione){thrownewRuntimeException(e);}}

然后报了如下错误:

其实这个参数错误,是因为每个枚举类都默认继承了Enum,而Enum类的构造方法又有两个参数,如下所示:

这时就需要一起放在我们的枚举类的参数列表中传入才行:

Constructor<?>ctor=cs.getDeclaredConstructor(String.class,int.class,String.class,int.class);

解决上述问题之后,此时又有一个错误如下所示:

点击第二行跳转过去看看源码:

总结

  1. Enum类同样有构造方法,但一定得是private修饰
  2. Enum类的每一个枚举元素都是【单例】
  3. Enum类型的类不能通过调用【构造方法】来创建实例
  4. Enum类型的类不能通过【反射】来创建新的实例,因为Enum的实例在编译时就已经确定,且JVM保证了这些实例的唯一性。

Ⅲ. 什么是Lambda表达式

Lambda表达式是JavaSE8中一个重要的新特性,它允许通过表达式来代替功能接口。

Lambda表达式和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(可以是一个表达式或一个代码块)。基本语法如下所示:

(parameters)->expression 或者(parameters)->{statements;}

举一些例子:

// 1. 不需要参数,返回值为 2()->2// 2. 接收⼀个参数,返回其2倍的值x->2*x// 3. 接受2个参数,并返回他们的和(x,y)->x+y// 4. 接收2个int型整数,返回他们的乘积(intx,inty)->x*y// 5. 接受⼀个 string 对象,并在控制台打印,不返回任何值(Strings)->System.out.print(s)

函数式接口定义:一个接口,且其中只有一个抽象方法(可以包含普通方法)

注意:如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。

举个例子:

@FunctionalInterfaceinterfaceNoParameterNoReturn{voidtest();// 合法!可以有普通方法defaultvoidtest2(){System.out.println("JDK1.8新特性,default默认⽅法可以有具体的实现");}}

Ⅳ.Lambda表达式的使用

@FunctionalInterfaceinterfaceMyInterface1{voidmyMethod();}@FunctionalInterfaceinterfaceMyInterface2{intmyMethod(inta,intb);}publicclassdemo2{publicstaticvoidmain(String[]args){MyInterface1myif1=()->System.out.println("无参无返回值方法");myif1.myMethod();MyInterface2myif2=(a,b)->a+b;System.out.println("有参数有返回值:"+myif2.myMethod(2,3));}}

☠ 注意事项:

  1. 参数类型可以省略。如果需要省略,每个参数的类型都要省略。

  2. 参数的小括号里面只有一个参数,那么小括号可以省略

  3. 如果方法体当中只有一句代码,那么大括号可以省略

  4. 如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字。

  5. lambda表达式捕获变量的规则,和匿名内部类是一样的,具体可以参考匿名内部类笔记

  6. lambda表达式是“函数式接口” 的一个匿名实现对象,区分开以下两者的区别:

    // Runnable是一个函数式接口,需要重写里面的run()方法!Runnabler=()->System.out.println("Hello, Lambda!");// Thread只是一个类,但是可以Thread(Runnable r)来构造,所以才需要new Thread,然后回到上面的问题!Threadt=newThread(()->System.out.println("work"));

列表排序的常用写法

1.基本比较(数值)

Integer.compare(a, b)

安全的数值比较,避免溢出:

list.sort((p1,p2)->Integer.compare(p1.getAge(),p2.getAge()));

适用于:

  • int,double,long等基本类型
  • 数值比较安全性优先(避免a - b的溢出问题)

2.方法引用 +Comparator.comparing

最简洁可读的写法:

list.sort(Comparator.comparing(Person::getAge));

优点:

  • 语义明确,别人一看就知道是按年龄排序
  • 支持链式调用.thenComparing(...)

3.多条件排序

list.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getName));

场景:

  • 先按主条件排(年龄)
  • 如果相同,再按次条件(名字)

4.倒序排序

两种常见方式:

// 方式1:reversed()list.sort(Comparator.comparing(Person::getAge).reversed());// 方式2:负数技巧(不推荐大数)list.sort((p1,p2)->Integer.compare(p2.getAge(),p1.getAge()));

5.处理 null 值

list.sort(Comparator.comparing(Person::getAge,Comparator.nullsLast(Integer::compareTo)));

说明:

  • nullsFirst→ null 在最前面
  • nullsLast→ null 在最后面

6.字符串比较(忽略大小写)

list.sort(Comparator.comparing(Person::getName,String.CASE_INSENSITIVE_ORDER));

7.完全自定义规则

当规则复杂(比如特殊业务逻辑)时:

list.sort((p1,p2)->{if(p1.getAge()==p2.getAge()){returnp1.getName().length()-p2.getName().length();}returnp1.getAge()-p2.getAge();});

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/13 17:34:00

跨平台部署实战指南:构建ARM架构与Docker镜像的完美融合方案

跨平台部署实战指南&#xff1a;构建ARM架构与Docker镜像的完美融合方案 【免费下载链接】OpenFLOW 项目地址: https://gitcode.com/gh_mirrors/openflow1/OpenFLOW 在现代软件开发中&#xff0c;您是否经常面临这样的困境&#xff1a;精心构建的应用在开发者的Intel M…

作者头像 李华
网站建设 2025/12/13 17:33:29

实体关系图设计终极指南:erd-editor 完整教程

实体关系图设计终极指南&#xff1a;erd-editor 完整教程 【免费下载链接】erd-editor Entity-Relationship Diagram Editor 项目地址: https://gitcode.com/gh_mirrors/er/erd-editor 在现代软件开发中&#xff0c;数据库设计是项目成功的关键因素。无论您是构建电商平…

作者头像 李华
网站建设 2025/12/13 17:31:32

TIA博途虚拟机:三版本一体化自动化工程解决方案

TIA博途虚拟机&#xff1a;三版本一体化自动化工程解决方案 【免费下载链接】TIA博途虚拟机文件V17V16V15.1可直接使用 本仓库提供了一个TIA博途虚拟机文件&#xff0c;包含TIA Portal V17、V16和V15.1版本&#xff0c;用户可以直接使用这些虚拟机进行开发和测试。虚拟机文件已…

作者头像 李华
网站建设 2025/12/16 20:08:47

17、Puppet 4新特性与Hiera数据分离实践

Puppet 4新特性与Hiera数据分离实践 1. Puppet 4新特性 1.1 新风格与Ruby DSL的变化 Puppet 4引入了新的风格,例如: class syslog_ng {... } include syslog_ng同时,Puppet 4不再支持Ruby DSL。在之前,有人会将.rb文件作为清单放在模块中,这些.rb文件包含Ruby代码,主…

作者头像 李华
网站建设 2025/12/13 17:29:35

腾讯混元3D引擎:10秒生成专业级3D模型的终极解决方案

腾讯混元3D引擎&#xff1a;10秒生成专业级3D模型的终极解决方案 【免费下载链接】Hunyuan3D-1 项目地址: https://ai.gitcode.com/hf_mirrors/tencent/Hunyuan3D-1 在当今数字内容爆炸式增长的时代&#xff0c;腾讯混元3D引擎作为革命性的AI驱动3D内容生成工具&#x…

作者头像 李华
网站建设 2025/12/13 17:28:58

vscode-jest测试插件v5版本终极使用指南

vscode-jest测试插件v5版本终极使用指南 【免费下载链接】vscode-jest The optimal flow for Jest based testing in VS Code 项目地址: https://gitcode.com/gh_mirrors/vs/vscode-jest vscode-jest是Visual Studio Code中最强大的Jest集成测试工具&#xff0c;专为提升…

作者头像 李华