1.枚举
枚举是在 JDK 1.5 引⼊的,主要是⽤来表示⼀组相同业务的值,⽐如我们要实现卖⻋的程序,我们要定 义⼀组颜⾊来穷举这辆⻋所提供的所有颜⾊,在没有枚举之前,我们是这样实现的:
public static int final RED = 1;
public static int final GREEN = 2;
public static int final BLACK = 3;
以上代码存在的主要问题有以下 3 个:
1. 代码可读性低,⽐如,当我们看到数字 2 时,并不能准确的知道它代表的具体是什么颜⾊,我们要 去代码⾥⾯查。
2. 参数传递很容易出错,以上代码类型为 int,所以在传递时理论上是可以接受所有的 int 值的,但只 有部分值是有效的颜⾊,所有很容易传递值出错。
3. 写法不够优雅,在外层(外边类)调⽤时,看到的都是⼀个个魔法数字,很让⼈很疑惑。 但有了枚举之后,我们就可以使⽤以下代码来组织所有的颜⾊了:
public enum ColorEnum {
//枚举的命名格式,所有的枚举值的使用全部用大写字母的形式定义
RED, GREEN, BLACK;
}
它的优点有以下⼏个:
1. 增强了代码的可读性。
2. 减少了传递参数的错误概率。
3. switch 判断更⽅便,语法清晰。
4. 代码⾜够简洁、优雅。
1.2 枚举常⽤⽅法
(1)values() 使⽤
以数组形式返回枚举类型的所有成员。
private static void eachEnum(){
ColorEnum[] arrs = ColorEnum.values();
for (ColorEnum item : arrs){
System.out.println(item);
}
}
(2)ordinal() 使⽤
获取枚举成员的索引位置。
private static void eachEnum(){
ColorEnum[] arrs = ColorEnum.values();
for (ColorEnum item : arrs){
int enumIdx = item.ordinal();
System.out.println(item + ":" + enumIdx);
}
}
(3)valueOf() 使⽤
将普通字符串转换为枚举实例。
public static void main(String[] args) {
// printColor(ColorEnum.GREEN);
// eachEnum();
String color = "RED";
try {
//将字符串转换成枚举示例
ColorEnum colorEnum = ColorEnum.valueOf(color);
printColor(colorEnum);
}catch(Exception e){
System.out.println("枚举类型转换失败");
}
}
(4)compareTo() 使⽤
⽐较两个枚举成员在定义时的顺序,返回值为 -1/0/1。
ColorEnum colorEnum = ColorEnum.GREEN;
ColorEnum colorEnum2 = ColorEnum.RED;
ColorEnum colorEnum3 = ColorEnum.BLACK;
System.out.println("颜色的顺序:红色,绿色,黑色");
int result1 = colorEnum.compareTo(colorEnum2);
System.out.println("绿色对比红色:" + result1);
int result2 = colorEnum.compareTo(colorEnum);
System.out.println("绿色对比绿色:" + result2);
int result3 = colorEnum2.compareTo(colorEnum3);
System.out.println("红色对比黑色:" + result3);
(5)枚举优缺点
优点:1. 增强了代码的可读性。
2. 减少了传递参数的错误概率。
3. switch 判断更⽅便,语法清晰。
4. 代码⾜够简洁、优雅。
5. 枚举有内置⽅法,功能更强⼤。
缺点:不可继承,⽆法扩展。
2.Lambda 表达式
Lambda 表达式是 JDK 8 中⼀个重要的新特性,lambda 表达式允许你通过表达式来代替功能接⼝(通 过表达式通过实现业务功能)。lambda 表达式就和⽅法⼀样,它提供了⼀个正常的参数列表和⼀个使 ⽤这些参数的主体(body,可以是⼀个表达式或⼀个代码块),Lambda 表达式(Lambda expression)可以看作是⼀个匿名函数。
2.1 为什么要⽤ Lambda?
1. 提供了更简单的语法和写代码的⽅式。
2. 取代匿名内部类。
3. 简化代码,⼲净整洁。
2.2 Lambda 语法
(⼊参) -> {实现代码}
表达式由 3 部分组成:
1. ⼊参 paramaters:类似⽅法中的形参列表,这⾥的参数是函数式接⼝⾥的参数。这⾥的参数 类型可以明确的声明也可不声明⽽由JVM隐含的推断。另外当只有⼀个推断类型时可以省略 掉圆括号。
2. ->:可理解为“被⽤于”的意思
3. 实现代码(⽅法体):可以是表达式也可以代码块,是函数式接⼝⾥⽅法的实现。代码块可 返回⼀个值或者什么都不反回,这⾥的代码块块等同于⽅法的⽅法体。如果是表达式,也可 以返回⼀个值或者什么都不返回。
Lambda 基础使⽤:
import java.util.Arrays;
import java.util.List;
public class LambdaTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("Java", "MySQL", "Spring");
//传统的循环并打印
for (String item : list) {
System.out.println(item);
}
//lambda
list.forEach((item) ->{
System.out.println(item);
});
//简洁
list.forEach(item -> System.out.println(item));
}
}
注意事项: 1. 如果 lambda 参数的⼩括号⾥⾯只有⼀个参数,那么⼩括号可以省略。
2. 如果⽅法体当中只有⼀句代码,那么⼤括号可以省略。
3. 如果⽅法体中只有⼀条语句,其是 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 表达式不能直接使⽤,它在使⽤之前必须初始化,lambda 表达式必须借助函数式接⼝来初始化。
2.3.1 函数式接⼝
函数式接⼝定义:⼀个接⼝有且只有⼀个抽象⽅法。
注意事项:
1. 如果⼀个接⼝只有⼀个抽象⽅法,那么该接⼝就是⼀个函数式接⼝。
2. 如果我们在某个接⼝上声明了注解,那么编译器就会按照函数式接⼝的定义 来要求该接⼝,这样如果有两个抽象⽅法,程序编译就会报错的。所以,从某种意义上来说,只要 你保证你的接⼝中只有⼀个抽象⽅法,你可以不加这个注解。加上就会⾃动进⾏检测的。
函数式接⼝的定义代码如下:
public interface MyFunctionalInterface {
void myMethod(Object...args);
}
有了函数式接⼝之后,我们就可以使⽤ lambda 表达式对其实例化了,实现代码如下:
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 修饰的,要保证在使⽤之前,没有修改,否 则就会报错。
public class LambdaTest {
public static void main(String[] args) {
int count = 100;
MyFunctionalInterface myFunctionalInterface = (o) ->{
for (Object item : o){
System.out.println("item:" + item);
}
System.out.println("Count:" + count);
};
myFunctionalInterface.myMethod("java","mysql","html");
}
}
2.5 Lambda 在集合中的使⽤
Lambda 表达式最有价值的作⽤就是可以配合集合⼀块使⽤。 Lambda 可以配合使⽤的⽅法列表如下:
Map的用法:
HashMap<String,String> map = new HashMap<String,String>(){{
put("java","java Value");
put("MySQL","MySQL Value");
}};
//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);
});
List 排序
List<Integer> list = Arrays.asList(5,3,4,6,7);
System.out.println("排序前:" + list);
list.sort(((o1, o2) -> {
return o1-o2;
}));
System.out.println("排序后: " + list);
List 查找
List<String> list = Arrays.asList("java","MySQL","Spring");
List<String> finds = list.stream().filter(s->s.equals("Spring")).collect(Collectors.toList());
System.out.println(finds);
2.6 Lambda 优缺点分
优点: 1. 代码简洁,开发迅速
2. ⽅便函数式编程
3. ⾮常容易进⾏并⾏计算
4. Java 引⼊ Lambda,改善了集合操作
缺点:1. 代码可读性变差
2. 在⾮并⾏计算中,很多计算未必有传统的 for 性能要⾼
3. 不容易进⾏调试