1.枚举
????????枚举是在 JDK 1.5 引?的,主要是用来表示?组相同业务的值,比如我们要实现卖车的程序,我们要定义?组颜色来穷举这辆?所提供的所有颜色,在没有枚举之前,我们是这样实现的:
public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;
以上代码存在的主要问题有以下 3 个:
- 代码可读性低,?如,当我们看到数字 2 时,并不能准确的知道它代表的具体是什么颜?,我们要去代码??查;
- 参数传递很容易出错,以上代码类型为 int,所以在传递时理论上是可以接受所有的 int 值的,但只有部分值是有效的颜?,所有很容易传递值出错;
- 写法不够优雅,在外层(外边类)调?时,看到的都是?个个?魔法数字?,很让?很疑惑。
但有了?枚举?之后,我们就可以使?以下代码来组织所有的颜?了:
public enum ColorEnum {
RED, GREEN, BLACK;
}
它的优点有以下几个:
- 增强了代码的可读性;
- 减少了传递参数的错误概率;
- switch 判断更?便,语法清晰;
- 代码?够简洁、优雅。
?
1.1 switch 判断
public enum ColorEnum {
RED, GREEN, BLACK;
public static void main(String[] args) {
ColorEnum colorEnum = ColorEnum.GREEN;
switch (colorEnum) {
case RED:
System.out.println("红?");
break;
case BLACK:
System.out.println("??");
break;
case GREEN:
System.out.println("绿?");
break;
default:
System.out.println("其他颜?");
break;
}
? }
}
?运行结果:
?
1.2 枚举的常用方法
?1.2.1 values() 使用
以数组形式返回枚举类型的所有成员。
public enum ColorEnum {
RED, GREEN, BLACK;
public static void main(String[] args) {
for (ColorEnum colorEnum : ColorEnum.values()) {
System.out.println(colorEnum);
}
}
}
执行结果:
1.2.2?ordinal() 使用
public enum ColorEnum2 {
RED, GREEN, BLACK;
public static void main(String[] args) {
for (ColorEnum colorEnum : ColorEnum.values()) {
System.out.println(colorEnum + ":" + colorEnum.ordinal());
}
}
}
执行结果:?
?1.2.3 valueOf() 使用
将普通字符串转换为枚举实例。
public enum ColorEnum3 {
RED, GREEN, BLACK;
public static void main(String[] args) {
ColorEnum color = ColorEnum.valueOf("BLACK");
System.out.println(color.ordinal());
}
}
执行结果:
?
1.2.3?compareTo() 使用
比较两个枚举成员在定义时的顺序,返回值为 枚举成员下标差值的int值。
public enum ColorEnum4 {
RED, GREEN, BLACK;
public static void main(String[] args) {
ColorEnum4 color1 = ColorEnum4.RED;
ColorEnum4 color2 = ColorEnum4.GREEN;
ColorEnum4 color3 = ColorEnum4.BLACK;
System.out.println("红色对比绿色:" + color1.compareTo(color2));
System.out.println("红色对比黑色:" + color1.compareTo(color3));
System.out.println("绿色对比黑色:" + color2.compareTo(color3));
System.out.println("绿色对比红色:" + color2.compareTo(color1));
System.out.println("黑色对比红色:" + color3.compareTo(color1));
System.out.println("黑色对比绿色:" + color3.compareTo(color2));
}
}
?运行结果:
?
1.3 枚举优缺点
优点:
- 增强了代码的可读性;
- 减少了传递参数的错误概率;
- switch 判断更?便,语法清晰;
- 代码?够简洁、优雅;
- 枚举有内置?法,功能更强?。
?缺点:
- 不可继承,?法扩展。
?
?2.Lambda 表达式
????????Lambda 表达式是 JDK 8 中?个重要的新特性,lambda 表达式允许你通过表达式来代替功能接口(通过表达式通过实现业务功能)。lambda 表达式就和?法?样,它提供了?个正常的参数列表和?个使?这些参数的主体(body,可以是?个表达式或?个代码块),Lambda 表达式(Lambda expression)可以看作是?个?匿名函数?。?
2.1 为什么要用?Lambda
原因有三个:
- 提供了更简单的语法和写代码的?式;
- 取代匿名内部类;
- 简化代码,干净整洁。
?
2.2 Lambda 语法
2.2.1 Lambda 表达式的基本语法如下:
(?参) -> {实现代码}
表达式由 3 部分组成:
- 入参 paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有?个推断类型时可以省略掉圆括号;
- ->:可理解为“被?于”的意思;
- 实现代码(方法体):可以是表达式也可以代码块,是函数式接???法的实现。代码块可返回?个值或者什么都不反回,这?的代码块块等同于?法的?法体。如果是表达式,也可以返回?个值或者什么都不返回。
?2.2.2 Lambda 基础使用:
public static void main(String[] args) {
List<String> lists = Arrays.asList("Hello", "World", "Java");
// 没使? lambda 之前
for (String list : lists) {
System.out.println(list);
}
System.out.println();
// 使? lambda 之后
lists.forEach(s -> System.out.println(s));
}
注意事项:
- 如果 lambda 参数的小括号里面只有?个参数,那么小括号可以省略;
- 如果?法体当中只有?句代码,那么?括号可以省略;
- 如果?法体中只有?条语句,其是 return 语句,那么?括号可以省略,且去掉 return 关键字。
?
2.3 Lambda 和函数式接口
?Lambda 表达式的写法有很多,比如以下这些:
// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收?个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受?个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
但是Lambda 表达式不能直接使用,它在使用之前必须初始化,lambda 表达式必须借助 函数式接口(@FunctionalInterface)来初始化。
?
函数式接口:
定义:?个有且只有?个抽象方法的接口。
?函数式接口的定义代码如下:
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
?注意事项:
- 如果?个接口只有?个抽象?法,那么该接口就是?个函数式接口;
- 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接?的定义来要求该接?,这样如果有两个抽象?法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接?中只有?个抽象方法,你可以不加这个注解。加上就会?动进?检测的。
??有了函数式接口之后,我们就可以使用?lambda 表达式对其实例化了,实现代码如下:?
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
public class LambdaExample {
public static void main(String[] args) {
// lambda 表达式借助函数式接?初始化
MyFunctionalInterface functionalInterface = (objects) -> {
for (Object o : objects) {
System.out.println(o.toString());
}
};
// 执? lambda 表达式
functionalInterface.myMethod("张三", "李四", "王五");
}
}
执行结果:
?
2.4 Lambda 的变量捕获
????????在 lambda 中获取变量和在匿名内部类获取变量的规则?致:也就是在 lambda 中,如果要获取外部的变量,那么这个变量要么是被 final 修饰,如果不是被 final 修饰的,要保证在使用之前,没有修改,否则就会报错。
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod(Object... args);
}
public class LambdaExample {
public static void main(String[] args) {
int count = 10;
MyFunctionalInterface functionalInterface = (objects) -> {
// count = 99; // 在使?之前,如果修改就会报错
for (Object o : objects) {
System.out.println(o.toString());
}
System.out.println("打印外部变量:" + count); // 可以正常执?
};
functionalInterface.myMethod("张三", "李四", "王五");
}
}
?运行结果:
将 count 值修改为 99 后会报错:
?
?2.5 Lambda 在集合中的使用
?????????Lambda 表达式最有价值的作?就是可以配合集合?块使?。Lambda 可以配合使?的?法列表如下:
2.5.1 Map 中的 forEach
HashMap<String, String> map = new HashMap<String, String>() {{
put("name", "Java");
put("desc", "Good");
}};
// jdk 1.8 之前
for (Map.Entry<String, String> item : map.entrySet()) {
System.out.println(item.getKey() + ":" + item.getValue());
}
System.out.println();
// lambda
map.forEach((k, v) -> System.out.println(k + ":" + v));
?2.5.2 List 排序
List<Integer> list = Arrays.asList(5, 3, 2, 7, 9);
System.out.println("排序前:" + list);
// 不使用 Lambda 表达式
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// 使用 Lambda 表达式
list.sort((o1, o2) -> o2 - o1);
System.out.println("排序后:" + list);
2.5.3 List 查找
List<String> list = Arrays.asList("Java", "Lambda", "Spring", "Lambda", "SpringBoot", "MyBatis");
// 1.8 之前
for (String item : list) {
if (item.equals("Lambda")) {
System.out.println("");
}
}
// lambda
List<String> finds = list.stream().filter(s -> s.equals("Lambda")).collect(Collectors.toList());
System.out.println(finds);
?
2.6 Lambda 优缺点分析
优点:
- 代码简洁,开发迅速;
- 方便函数式编程;
- 非常容易进行并行计算;
- Java 引? Lambda,改善了集合操作。
缺点?:
- 代码可读性变差;
- 在非并行计算中,很多计算未必有传统的 for 性能要高;
- 不容易进行调试。
|