news 2026/4/23 18:51:24

【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进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 10:08:40

concurrent.futures 全面教程:常用 API 串联与实战指南

大家好&#xff0c;我是jobleap.cn的小九。 concurrent.futures 是 Python 标准库中用于简化并发编程的核心模块&#xff0c;基于抽象的 Executor 类封装了 ThreadPoolExecutor&#xff08;线程池&#xff09;和 ProcessPoolExecutor&#xff08;进程池&#xff09;&#xff0c…

作者头像 李华
网站建设 2026/4/23 17:22:25

Dijkstra - 单源最短路径

算法:Dijkstra [堆优化(优先队列)]求解:单源最短路径核心思想&#xff1a;贪心,每次从未确定最短距离的节点中,选择距离源点最近的节点,用该节点更新其邻接点的距离。这是一个堆优化的Dijkstra最短路径算法实现。让我为您详细解析每个部分&#xff1a;一、数据结构解析1. 邻接表…

作者头像 李华
网站建设 2026/4/23 10:59:57

亲手搭建原子级观测设备:OpenSTM终极指南

亲手搭建原子级观测设备&#xff1a;OpenSTM终极指南 【免费下载链接】OpenSTM OpenSTM - 一个扫描隧道显微镜项目&#xff0c;可能用于科研或精密工程领域。 项目地址: https://gitcode.com/gh_mirrors/op/OpenSTM 想要亲眼看到原子的排列吗&#xff1f;现在&#xff0…

作者头像 李华
网站建设 2026/4/19 22:12:06

突破性进展:NVIDIA OpenReasoning推理模型重塑AI编程新范式

突破性进展&#xff1a;NVIDIA OpenReasoning推理模型重塑AI编程新范式 【免费下载链接】OpenReasoning-Nemotron-14B 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/OpenReasoning-Nemotron-14B 在人工智能与编程深度融合的时代背景下&#xff0c;NVIDIA最新推…

作者头像 李华
网站建设 2026/4/18 9:46:13

Qwen3 Embedding模型终极指南:vLLM Ascend快速部署与性能调优

在人工智能语义理解领域&#xff0c;Qwen3 Embedding模型系列以其卓越的多语言能力和灵活的向量表示&#xff0c;为文本检索与重排序任务带来了革命性突破。本指南将带您深度探索基于vLLM Ascend部署这一前沿技术的完整流程。 【免费下载链接】Qwen3-Reranker-8B 项目地址: …

作者头像 李华