目录 认识枚举 全文重点:枚举在单例模式中为什么是安全的? Lambda 表达式 概念: 函数式接口 lambda表达式的基本使用: lambda表达式的语法精简: lambda表达式的变量捕获 Lambda在集合当中的使用 在 Collection接口中的使用: 在List中的使用 lambda表达式的总结: 认识枚举枚举(Enumeration)是一种数据类型,它由一组预定义的常量组成,这些常量通常被称为枚举的成员或枚举值。 枚举的作用,把我们想要描述的东西举例出来,例如颜色。因为在Java中并没有一个特殊的数据类型是表示颜色的。 下列直接列出枚举的简单使用的方法: [code]enum TestEnum { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { TestEnum testEnum2 = TestEnum.BLACK; switch (testEnum2) { case RED: System.out.println("red"); break; case BLACK: System.out.println("black"); break; case WHITE: System.out.println("WHITE"); break; case GREEN: System.out.println("black"); break; default: break; } } }[/code]上述场景就是:一个简单使用枚举类型的场景。 从上面代码可以看出枚举:enum 其实有点像类,里面也可以有属性和方法。不同的是enum的第一行必须是你要枚举的常量。否则编译器会直接报错。 带参数的使用案例: 这是带有构造方法的枚举,所以在第一行的枚举常量中我们就必须传参。 注意:枚举的构造方法默认是私有的(重要) [code]enum TestEnum1 { RED("red",1),BLACK("black",2),WHITE("white",3),GREEN("green",4); private String name; private int key; /** * 1、当枚举对象有参数后,需要提供相应的构造函数 * 2、枚举的构造函数默认是私有的 这个一定要记住 * @param name * @param key */ private TestEnum1 (String name,int key) { this.name = name; this.key = key; } public static TestEnum1 getEnumKey (int key) { for (TestEnum1 t: TestEnum1.values()) { if(t.key== key) { return t; } } return null; } public static void main(String[] args) { System.out.println(getEnumKey(2)); } }[/code]![]() 枚举还有属于自己的的方法: values() 以数组形式返回枚举类型的所有成员 ordinal() 获取枚举成员的索引位置 valueOf() 将普通字符串转换为枚举实例 compareTo() 比较两个枚举成员在定义时的顺序 [code] enum TestEnum2 { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { TestEnum2[] testEnum2 = TestEnum2.values(); for (int i = 0; i < testEnum2.length; i++) { System.out.println(testEnum2[i] + " " + testEnum2[i].ordinal()); } System.out.println("========================="); System.out.println(TestEnum2.valueOf("GREEN")); } }[/code]![]() compareTo方法使用案例: [code]enum TestEnum { RED,BLACK,GREEN,WHITE; public static void main(String[] args) { //拿到枚举实例BLACK TestEnum testEnum = TestEnum.BLACK; //拿到枚举实例RED TestEnum testEnum21 = TestEnum.RED; System.out.println(testEnum.compareTo(testEnum21)); System.out.println(BLACK.compareTo(RED)); System.out.println(RED.compareTo(BLACK)); } }[/code]![]() 枚举的优缺点: 优点: 简单安全,枚举具有内置方法 缺点:无法继承,不可扩展 全文重点:枚举在单例模式中为什么是安全的?枚举实现单例的安全性基于以下几个原因:
那么接下来我们就重点解析一下第二点:枚举是怎么防止反射攻击? 下面我们尝试一下反射获取构造方法,并尝试实例化出一个对象。 [code]enum TestEnum1 { RED("red",1),BLACK("black",2),WHITE("white",3),GREEN("green",4); private String name; private int key; /** * 1、当枚举对象有参数后,需要提供相应的构造函数 * 2、枚举的构造函数默认是私有的 这个一定要记住 * @param name * @param key */ private TestEnum1 (String name,int key) { this.name = name; this.key = key; } public static TestEnum1 getEnumKey (int key) { for (TestEnum1 t: TestEnum1.values()) { if(t.key== key) { return t; } } return null; } public static void reflectPrivateConstructor() { try { Class<?> classStudent = Class.forName("TestEnum"); //注意传入对应的参数,获得对应的构造方法来构造对象,当前枚举类是提供了两个参数分别是String和int。 Constructor<?> declaredConstructorStudent= classStudent.getDeclaredConstructor(String.class, int.class); //设置为true后可修改访问权限 declaredConstructorStudent.setAccessible(true); Object objectStudent = declaredConstructorStudent.newInstance("绿色",666); TestEnum testEnum = (TestEnum) objectStudent; System.out.println("获得枚举的私有构造函数:"+testEnum); } catch (Exception ex) { ex.printStackTrace(); } }[/code]![]() 显然编译器已经报错,并直接给出提示,不能通过反射,创建出一个枚举实例。 那么我们就看一下源码,来看看代码是怎样抛出异常,阻止反射枚举获取实例。 ![]() 跳转到源码当中就发现了,(clazz.getModifiers() & Modifier.ENUM) != 0,的第二个条件直接忽略了枚举,当Constructor中发现反射对象为枚举时,就直接抛出异常了。这就是枚举实现单例模式时安全的原因之一。 Lambda 表达式概念:Lambda表达式在Java中是一种重要的高级特性,它允许开发者以更简洁的方式定义和使用函数,特别是在处理集合和多线程编程时提供了更为简洁和高效的解决方案。
(parameters) -> expression(表达式) (parameters) ->{ statements; } (代码块) 这里把expression和statements统称为方法体 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反 回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。 lambda表达式代码示例: [code]// 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) @FunctionalInterface interface NoParameterNoReturn { //注意:只能有一个方法 void test(); }[/code]那么lambda表达式在哪使用,怎么使用呢?那么我们就需要先认识函数式接口!!! 函数式接口
定义方式(两种): [code]interface NoParameterNoReturn { //注意:只能有一个方法 void test(); }[/code]或: [code]@FunctionalInterface interface NoParameterNoReturn { void test(); default void test2() { System.out.println("JDK1.8新特性,default默认方法可以有具体的实现"); } }[/code]可以简单理解为:lambda就是用来简化函数式接口的使用。 lambda表达式的基本使用:不使用lambda表达式的形式: [code]@FunctionalInterface interface NoParameterNoReturn { void test(); } public class T{ public static void main(String[] args) { NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){ @Override public void test() { System.out.println("hello"); } }; noParameterNoReturn.test(); } } [/code]向上面的代码,就略显麻烦。下面就展示各种接口的lambda表达式的使用方法: 以下还不是最精简的lambda表达式: [code] //无返回值无参数 @FunctionalInterface interface NoParameterNoReturn { void test(); } //无返回值一个参数 @FunctionalInterface interface OneParameterNoReturn { void test(int a); } //无返回值多个参数 @FunctionalInterface interface MoreParameterNoReturn { void test(int a,int b); } //有返回值无参数 @FunctionalInterface interface NoParameterReturn { int test(); } //有返回值一个参数 @FunctionalInterface interface OneParameterReturn { int test(int a); } //有返回值多参数 @FunctionalInterface interface MoreParameterReturn { int test(int a,int b); } public class T{ public class TestDemo { public static void main(String[] args) { NoParameterNoReturn noParameterNoReturn = ()->{ System.out.println("无参数无返回值"); }; noParameterNoReturn.test(); OneParameterNoReturn oneParameterNoReturn = (int a)->{ System.out.println("一个参数无返回值:"+ a); }; oneParameterNoReturn.test(10); MoreParameterNoReturn moreParameterNoReturn = (int a,int b)->{ System.out.println("多个参数无返回值:"+a+" "+b); }; moreParameterNoReturn.test(20,30); NoParameterReturn noParameterReturn = ()->{ System.out.println("有返回值无参数!"); return 40; }; //接收函数的返回值 int ret = noParameterReturn.test(); System.out.println(ret); OneParameterReturn oneParameterReturn = (int a)->{ System.out.println("有返回值有一个参数!"); return a; }; ret = oneParameterReturn.test(50); System.out.println(ret); MoreParameterReturn moreParameterReturn = (int a,int b)->{ System.out.println("有返回值多个参数!"); return a+b; }; ret = moreParameterReturn.test(60,70); System.out.println(ret); } } }[/code]lambda表达式的语法精简:
以上就是精简过后的lambda表达式。 lambda表达式的变量捕获在下面代码当中的变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的 你要保证在使用 之前,没有修改。如下代码就是错误的代码 : ![]() Lambda在集合当中的使用在 Collection接口中的使用:正常用法: [code]public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("bit"); list.add("hello"); list.add("lambda"); list.forEach(new Consumer<String>(){ @Override public void accept(String str){ //简单遍历集合中的元素。 System.out.print(str+" "); } }); }[/code]使用lambda表达式: 相当于实现了Consumer<String>中的 void accept(String str)方法。 [code]public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("bit"); list.add("hello"); list.add("lambda"); //表示调用一个,不带有参数的方法,其执行花括号内的语句,为原来的函数体内容。 list.forEach(s -> { System.out.println(s); }); }[/code]在List中的使用正常使用方法: [code]public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("bit"); list.add("hello"); list.add("lambda"); list.sort(new Comparator<String>() { @Override public int compare(String str1, String str2) { //注意这里比较长度 return str1.length() - str2.length(); } }); System.out.println(list); }[/code]lambda表示式用法: 相当于实现了Comparator<String>中的int compare(String str1, String str2)方法 [code]public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("bit"); list.add("hello"); list.add("lambda"); //调用带有2个参数的方法,且返回长度的差值 list.sort((str1, str2) -> str1.length() - str2.length()); System.out.println(list); }[/code]lambda表达式的总结:Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
免责声明:本内容来源于网络,如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |