当前位置:   article > 正文

反射枚举及lambda的使用_lambdaquerywrapper反射

lambdaquerywrapper反射

目录

一、反射

1.定义

2.用途

3.反射基本信息

4.反射相关的类

(1)Class类(反射机制的起源)

(2)Field类的相关方法

(3)Method类的相关方法

(4)Constructor类的相关方法

(5)获得类中注解相关的方法

(6)获得Class对象的三种方式

(7)反射的使用

五、反射优点和缺点

二、枚举

1.背景及定义

2.枚举的使用

3.枚举的优缺点

4.枚举和反射

5.一条重要的题

三、lambda表达式

1.背景

2.基本语法

3.基本使用

4.变量捕获

5.lambda在集合当中的使用

(1)Collection接口

(2)List接口

 (3)Map接口

 (6)lambda的优缺点


一、反射

1.定义

Java 的反射(reflection)机制是在 运行 状态中,对于任意一个类,都能够知道这个类的 所有属性和方法 ;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称java 语言的反射(reflection)机制。

2.用途

(1)在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java 的反射机制通过反射来获取所需的私有成员或是方法 。
(2)反射最重要的用途就是开发各种通用框架,比如在 spring 中,我们将所有的类 Bean 交给 spring 容器管理,无论是XML 配置 Bean 还是注解配置,当我们从容器中获取 Bean 来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring 根据这些信息,需要创建那些 Bean spring 就动态的创建这些类。

3.反射基本信息

Java 程序中许多对象在运行时会出现两种类型: 运行时类型 (RTTI) 和编译时类型 ,例如 Person p = new Student();这句代码中 p 在编译时类型为 Person ,运行时类型为 Student 。程序需要在运行时发现对象和类的真实信心。而通过用反射程序就能判断出该对象和类属于哪些类。

4.反射相关的类

类名
用途
Class
代表类的实体,在运行的 Java 应用程序中表示类和接口
Field
代表类的成员变量 / 类的属性
Method类
代表类的方法
Constructor
代表类的构造方法

(1)Class类(反射机制的起源)

①Class类代表类的实体,在运行的 Java 应用程序中表示类和接口  。Java文件被编译后,生成了 .class 文件, JVM 此时就要去解读 .class 文件 , 被编译后的 Java 文件 .class 也被 JVM 解析为一个对象,这个对象就是 java.lang.Class . 这样当程序在运行时,每个类 文件就最终变成了 Class 类对象的一个实例。我们通过Java 的反射机制应用到这个实例,就可以去 获得甚至去添加改变这个类的属性和动作 ,使得这个类成为一个动态的类 。
②Class类的相关方法
方法
用途
getClassLoader()
获得类的加载器
getDeclaredClasses()
返回一个数组,数组中包含该类中所有类和接口类的对象 ( 包括私有的 )
forName(String className)
根据类名返回类的对象
newInstance()
创建类的实例
getName()
获得类的完整路径名字

(2)Field类的相关方法

方法用途
getField(String name)
获得某个公有的属性对象
getFields()
获得所有公有的属性对象
getDeclaredField(String name)
获得某个属性对象
getDeclaredFields()
获得所有属性对象

(3)Method类的相关方法

方法用途
getMethod(String name, Class...<?> parameterTypes)
获得该类某个公有的方法
getMethods()
获得该类所有公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes)
获得该类某个方法
getDeclaredMethods()
获得该类所有方法

(4)Constructor类的相关方法

方法用途
getConstructor(Class...<?> parameterTypes)
获得该类中与参数类型匹配的公有构造方法
getConstructors()
获得该类的所有公有构造方法
getDeclaredConstructor(Class...<?> parameterTypes)
获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()
获得该类所有构造方法

(5)获得类中注解相关的方法

方法用途
getAnnotation(Class annotationClass)
返回该类中与参数类型匹配的公有注解对象
getAnnotations()
返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)
返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()
返回该类所有的注解对象

(6)获得Class对象的三种方式

在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的 Class 对象,然后通过 Class 对象的核心方法,达到反射的目的,即:在运行 状态中,对于任意一个类,都能够知道这个类的 所有属性和方法 ;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息。
第一种 ,使用 Class.forName(" 类的全路径名 "); 静态方法。 前提:已明确类的全路径名。
第二种 ,使用 .class 方法。 说明:仅适合在编译前就已经明确要操作的 Class
第三种 ,使用类对象的 getClass() 方法
  1. package reflect;
  2. class Student{
  3. //私有属性name
  4. private String name = "bit";
  5. //公有属性age
  6. public int age = 18;
  7. //不带参数的构造方法
  8. public Student(){
  9. System.out.println("Student()");
  10. }
  11. private Student(String name,int age) {
  12. this.name = name;
  13. this.age = age;
  14. System.out.println("Student(String,name)");
  15. }
  16. private void eat(){
  17. System.out.println("i am eat");
  18. }
  19. public void sleep(){
  20. System.out.println("i am a pig");
  21. }
  22. private void function(String str) {
  23. System.out.println(str);
  24. }
  25. @Override
  26. public String toString() {
  27. return "Student{" +
  28. "name='" + name + '\'' +
  29. ", age=" + age +
  30. '}';
  31. }
  32. }
  33. public class TestDemo2 {
  34. public static void main(String[] args) throws ClassNotFoundException{
  35. Class<?> c1 = Class.forName("reflect.Student");
  36. Class<?> c2 = Student.class;
  37. Student student = new Student();
  38. Class<?> c3 = student.getClass();
  39. System.out.println(c1 == c2);
  40. System.out.println(c1 == c3);
  41. System.out.println(c2 == c3);
  42. //全部都是true,说明不管使用哪种方式获取Class对象,该对象只有一个
  43. }
  44. }

(7)反射的使用

(以下代码与上面的代码在同一个包底下)

  1. package reflect;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. public class ReflectClassDemo {
  7. //通过Class类的newInstance方法获取学生的一个实例
  8. public static void reflectNewInstance() {
  9. try{
  10. Class<?> c1 = Class.forName("reflect.Student");
  11. Student student = (Student) c1.newInstance();//newInstance()的返回值是T类型
  12. System.out.println(student);
  13. } catch (ClassNotFoundException e) {
  14. e.printStackTrace();
  15. } catch (InstantiationException e) {
  16. e.printStackTrace();
  17. } catch (IllegalAccessException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. // 反射私有或公有的构造方法 屏蔽内容为获得公有的构造方法
  22. public static void reflectPrivateConstructor() {
  23. try{
  24. Class<?> c1 = Class.forName("reflect.Student");
  25. Constructor<?> constructor = c1.getDeclaredConstructor(String.class, int.class);
  26. constructor.setAccessible(true);
  27. Student student = (Student)constructor.newInstance("abc",18);
  28. System.out.println(student);
  29. } catch (ClassNotFoundException e) {
  30. e.printStackTrace();
  31. } catch (NoSuchMethodException e) {
  32. e.printStackTrace();
  33. } catch (InvocationTargetException e) {
  34. e.printStackTrace();
  35. } catch (InstantiationException e) {
  36. e.printStackTrace();
  37. } catch (IllegalAccessException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. //反射私有属性(获取私有或公开的)
  42. public static void reflectPrivateField() {
  43. try {
  44. Class<?> c1 = Class.forName("reflect.Student");
  45. Student student = (Student) c1.newInstance();
  46. Field field = c1.getDeclaredField("name");
  47. field.setAccessible(true);
  48. field.set(student,"zhangssan");
  49. System.out.println(student);
  50. } catch (ClassNotFoundException e) {
  51. e.printStackTrace();
  52. } catch (InstantiationException e) {
  53. e.printStackTrace();
  54. } catch (IllegalAccessException e) {
  55. e.printStackTrace();
  56. } catch (NoSuchFieldException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. //反射私有的方法
  61. public static void reflectPrivateMethod() {
  62. try {
  63. Class<?> c1 = Class.forName("reflect.Student");
  64. Student student = (Student) c1.newInstance();
  65. Method method = c1.getDeclaredMethod("function", String.class);
  66. method.setAccessible(true);
  67. method.invoke(student,"我是私有方法的参数");
  68. } catch (ClassNotFoundException e) {
  69. e.printStackTrace();
  70. } catch (InstantiationException e) {
  71. e.printStackTrace();
  72. } catch (IllegalAccessException e) {
  73. e.printStackTrace();
  74. } catch (NoSuchMethodException e) {
  75. e.printStackTrace();
  76. } catch (InvocationTargetException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. public static void main(String[] args) {
  81. //reflectNewInstance();
  82. //reflectPrivateConstructor();
  83. //reflectPrivateField();
  84. reflectPrivateMethod();
  85. }
  86. }

五、反射优点和缺点

优点:
1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
3. 反射已经运用在了很多流行框架如: Struts Hibernate Spring 等等。
缺点:
1. 使用反射会有效率问题。会导致程序效率降低。
2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。

二、枚举

1.背景及定义

枚举是在 JDK1.5 以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:
  1. public static int final RED = 1;
  2. public static int final GREEN = 2;
  3. public static int final BLACK = 3;
但是常量举例有不好的地方,例如:可能碰巧有个数字 1 ,但是他有可能误会为是 RED ,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1.
  1. public enum TestEnum {
  2. RED,BLACK,GREEN;
  3. }
优点:将常量组织起来统一进行管理
场景:错误状态码,消息类型,颜色的划分,状态机等等 ....
本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了 这个类

2.枚举的使用

(1)switch语句里面:

  1. public enum TestEnum {
  2. RED,BLACK,GREEN,WHITE;
  3. public static void main(String[] args) {
  4. TestEnum testEnum2 = TestEnum.BLACK;
  5. switch (testEnum2) {
  6. case RED:
  7. System.out.println("red");
  8. break;
  9. case BLACK:
  10. System.out.println("black");
  11. break;
  12. case WHITE:
  13. System.out.println("WHITE");
  14. break;
  15. case GREEN:
  16. System.out.println("black");
  17. break;
  18. default:
  19. break;
  20. }
  21. }
  22. }
(2)常用方法
方法名称描述
values()
以数组形式返回枚举类型的所有成员
ordinal()
获取枚举成员的索引位置
valueOf()
将普通字符串转换为枚举实例
compareTo()
比较两个枚举成员在定义时的顺序
  1. public enum TestEnum {
  2. RED,BLACK,GREEN,WHITE;
  3. public static void main(String[] args) {
  4. TestEnum[] testEnums = TestEnum.values();
  5. for (int i = 0; i < testEnums.length; i++) {
  6. System.out.println(testEnums[i] + "-->" + testEnums[i].ordinal());
  7. }
  8. }
  9. }
  1. public enum TestEnum {
  2. RED,BLACK,GREEN,WHITE;
  3. public static void main(String[] args) {
  4. TestEnum testEnum = TestEnum.valueOf("RED");//把字符串变成对应的枚举对象
  5. System.out.println(testEnum);//RED
  6. System.out.println(RED.compareTo(GREEN));//-2
  7. System.out.println(BLACK.compareTo(RED));//1
  8. }
  9. }

 (3)枚举的构造方法默认是私有的

  1. public enum TestEnum {
  2. RED("red",1),BLACK(),GREEN,WHITE;//它属于对象,当我们在它们后面加括号后相当于调用构造方法了
  3. public String color;
  4. public int ordinal;
  5. //构造方法默认是私有的
  6. TestEnum(String color,int ordinal){
  7. this.color = color;
  8. this.ordinal = ordinal;
  9. }
  10. TestEnum(){
  11. }
  12. }

3.枚举的优缺点

优点:
1. 枚举常量更简单安全 。
2. 枚举具有内置方法 ,代码更优雅
缺点:
1. 不可继承,无法扩展

4.枚举和反射

既然枚举的构造方法是私有的,那么是否可以通过反射来获取到枚举对象的实例呢?

  1. package enumdemo;
  2. public enum TestEnum {
  3. RED("red",1),BLACK("black",3),GREEN("green",8), WHITE("white",2);
  4. public String color;
  5. public int ordinal;
  6. //构造方法默认是私有的
  7. TestEnum(String color,int ordinal){
  8. //super();
  9. this.color = color;
  10. this.ordinal = ordinal;
  11. }
  12. }
  1. package enumdemo;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.InvocationTargetException;
  4. public class TestEnumReflect {
  5. public static void reflectPrivateConstructor(){
  6. try{
  7. Class<?> classEnum = Class.forName("enumdemo.TestEnum");
  8. Constructor<?> declaredConstructorStudent =
  9. classEnum.getDeclaredConstructor(String.class,int.class);
  10. declaredConstructorStudent.setAccessible(true);
  11. Object objectStudent = declaredConstructorStudent.newInstance("green",666);
  12. TestEnum testEnum = (TestEnum) objectStudent;
  13. System.out.println("获得枚举的私有构造函数:"+testEnum);
  14. } catch (ClassNotFoundException e) {
  15. e.printStackTrace();
  16. } catch (NoSuchMethodException e) {
  17. e.printStackTrace();
  18. } catch (InvocationTargetException e) {
  19. e.printStackTrace();
  20. } catch (InstantiationException e) {
  21. e.printStackTrace();
  22. } catch (IllegalAccessException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. public static void main(String[] args) {
  27. reflectPrivateConstructor();
  28. }
  29. }

编译并运行该代码,输出如下:

java.lang.NoSuchMethodException: TestEnum.<init>(java.lang.String, int)的意思 就是没有对应的构造方法,但是我们提供的枚举的构造方法就是两个参数分别是String 和 int 啊!问题出现在哪里呢?我们说过的,我们所有的枚举类,都是默认继承与 java.lang.Enum , 继承了父类除构造函数外的所有东西,并且子类要帮助父类进行构造! 而我们写的类,并没有帮助父类构造!所以我们要在自己的枚举类里面,提供super 吗?不是的,枚举比较特殊,虽然我们写的是两个,但是默认他还添加了两个参数,哪两个参数呢?我们看一下Enum 类的源码:

 

 那么现在我们来修改一下它吧!

  1. package enumdemo;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.InvocationTargetException;
  4. public class TestEnumReflect {
  5. public static void reflectPrivateConstructor(){
  6. try{
  7. Class<?> classEnum = Class.forName("enumdemo.TestEnum");
  8. Constructor<?> declaredConstructorStudent =
  9. classEnum.getDeclaredConstructor(String.class,int.class,String.class,int.class);
  10. declaredConstructorStudent.setAccessible(true);
  11. Object objectStudent = declaredConstructorStudent.newInstance("green",666,"abc",999);
  12. TestEnum testEnum = (TestEnum) objectStudent;
  13. System.out.println("获得枚举的私有构造函数:"+testEnum);
  14. } catch (ClassNotFoundException e) {
  15. e.printStackTrace();
  16. } catch (NoSuchMethodException e) {
  17. e.printStackTrace();
  18. } catch (InvocationTargetException e) {
  19. e.printStackTrace();
  20. } catch (InstantiationException e) {
  21. e.printStackTrace();
  22. } catch (IllegalAccessException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. public static void main(String[] args) {
  27. reflectPrivateConstructor();
  28. }
  29. }

编译并运行该代码,输出如下: 

 它还在报错,这是为什么呢?我们来看一下部分底层的源码:

 这说明:枚举十分安全,不能通过反射来获取枚举的实例对象

总结:

枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承与 java.lang.Enum

②枚举可以避免反射和序列化问题

5.一条重要的题

写一个单例模式

(1)普通实现

  1. public class Singleton {
  2. private volatile static Singleton uniqueInstance;
  3. private Singleton() {}
  4. public static Singleton getInstance() {
  5. if (uniqueInstance == null) {
  6. synchronized (Singleton.class){
  7. if(uniqueInstance == null){//进入区域后,再检查一次,如果仍是null,才创建实例
  8. uniqueInstance = new Singleton();
  9. }
  10. }
  11. }
  12. return uniqueInstance;
  13. }
  14. }

(2)用静态内部类实现一个单例模式

  1. class Singleton { /** 私有化构造器 */
  2. private Singleton() { }/** 对外提供公共的访问方法 */
  3. public static Singleton getInstance() {
  4. return UserSingletonHolder.INSTANCE;
  5. }/** 写一个静态内部类,里面实例化外部类 */
  6. private static class UserSingletonHolder {
  7. private static final Singleton INSTANCE = new Singleton();
  8. }
  9. }
  10. public class Main {
  11. public static void main(String[] args) {
  12. Singleton u1 = Singleton.getInstance();
  13. Singleton u2 = Singleton.getInstance();
  14. System.out.println("两个实例是否相同:"+ (u1==u2));
  15. }
  16. }

(3)用枚举实现一个单例模式

  1. public enum TestEnum {
  2. INSTANCE; public TestEnum getInstance(){
  3. return INSTANCE;
  4. }
  5. public static void main(String[] args) {
  6. TestEnum singleton1=TestEnum.INSTANCE;
  7. TestEnum singleton2=TestEnum.INSTANCE;
  8. System.out.println("两个实例是否相同:"+(singleton1==singleton2));
  9. }
  10. }

三、lambda表达式

1.背景

Lambda 表达式是 Java SE 8 中一个重要的新特性。 lambda 表达式允许你通过表达式来代替功能接口。 lambda 表达式就和方法一样, 它提供了一个正常的参数列表和一个使用这些参数的主体 (body, 可以是一个表达式或一个代码块) Lambda 表达式( Lambda expression )可以看作是一个匿名函数 ,基于数学中的 λ 演算得名,也可称为闭包(Closure

2.基本语法

(i)基本语法 : (parameters) -> expression (parameters) ->{ statements; }
Lambda 表达式由三部分组成:
(1)  paramaters :类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM 隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
(2)->:可理解为 被用于 的意思
(3)方法体 :可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不返回,这里的代码块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。
举几个例子:
不需要参数,返回值为 2                       () -> 2
接收一个参数(数字类型),返回其2倍的值                x -> 2 * x
接受2个参数(数字),并返回他们的和                   (x, y) -> x + y
接收2个int型整数,返回他们的乘积                  (int x, int y) -> x * y
接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)                  (String s) -> System.out.print(s)
(ii)函数式接口: 一个接口有且只有一个抽象方法
注意:
①如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
②如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
  1. package lambdademo;
  2. //函数式接口(只有一个抽象方法)
  3. @FunctionalInterface//这个注释修饰这个接口,说明它是函数式接口
  4. interface NoParameterNoReturn{
  5. void test();
  6. }
  7. public class TestDemo {
  8. public static void main(String[] args) {
  9. //简化的写法
  10. NoParameterNoReturn noParameterNoReturn = () -> System.out.println("重写方法!");
  11. noParameterNoReturn.test();
  12. }
  13. public static void main1(String[] args) {
  14. NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){
  15. @Override
  16. public void test(){
  17. System.out.println("重写方法!");
  18. }
  19. };
  20. noParameterNoReturn.test();
  21. }
  22. }

3.基本使用

  1. //没有返回值,没有参数
  2. @FunctionalInterface//这个注释修饰这个接口,说明它是函数式接口
  3. interface NoParameterNoReturn{
  4. void test();
  5. }
  6. //无返回值一个参数
  7. @FunctionalInterface
  8. interface OneParameterNoReturn {
  9. void test(int a);
  10. }
  11. //无返回值多个参数
  12. @FunctionalInterface
  13. interface MoreParameterNoReturn {
  14. void test(int a,int b);
  15. }
  16. //有返回值无参数
  17. @FunctionalInterface
  18. interface NoParameterReturn {
  19. int test();
  20. }
  21. //有返回值一个参数
  22. @FunctionalInterface
  23. interface OneParameterReturn {
  24. int test(int a);
  25. }
  26. //有返回值多参数
  27. @FunctionalInterface
  28. interface MoreParameterReturn {
  29. int test(int a,int b);
  30. }
  31. public class TestDemo {
  32. public static void main(String[] args) {
  33. OneParameterNoReturn oneParameterNoReturn = (a) ->{System.out.println(a);};
  34. oneParameterNoReturn.test(10);
  35. //优化
  36. OneParameterNoReturn oneParameterNoReturn2 = a ->System.out.println(a);
  37. oneParameterNoReturn.test(10);
  38. //继续优化
  39. OneParameterNoReturn oneParameterNoReturn3 = System.out::println;
  40. oneParameterNoReturn.test(10);
  41. MoreParameterNoReturn moreParameterNoReturn = (a,b) -> {//理论上来说要写(int a,int b)但是因为a,b同类型,所以两个int都可以省略
  42. System.out.println(a+b);
  43. };
  44. moreParameterNoReturn.test(10,20);
  45. NoParameterReturn noParameterReturn = () -> {return 10;};
  46. int ret = noParameterReturn.test();
  47. System.out.println(ret);
  48. //简写:
  49. NoParameterReturn noParameterReturn2 = () -> 10;
  50. int ret2 = noParameterReturn2.test();
  51. System.out.println(ret2);
  52. OneParameterReturn oneParameterReturn = a -> a + 11;
  53. System.out.println(oneParameterReturn.test(10));
  54. MoreParameterReturn moreParameterReturn = (a,b) -> a+b;
  55. System.out.println(moreParameterReturn.test(1,2));
  56. }
  57. }
Lambda 表达式本质是一个匿名函数,函数的方法是:返回值 方法名 参数列表 方法体。在, Lambda表达式中我们只需要关心参数列表方法体。
语法精简:
①参数类型可以省略,如果需要省略,每个参数的类型都要省略。
②  参数的小括号里面只有一个参数,那么小括号可以省略
③  如果方法体当中只有一句代码,那么大括号可以省略
④  如果方法体中只有一条语句,其是 return 语句,那么大括号可以省略,且去掉 return 关键字。

4.变量捕获

  1. package lambdademo;
  2. class Test {
  3. public void func(){
  4. System.out.println("func()");
  5. }
  6. }
  7. public class TestDemo2 {
  8. public static void main(String[] args) {
  9. int a = 100;
  10. //a = 99;//error
  11. new Test() {
  12. @Override
  13. public void func() {
  14. System.out.println("我是内部类,且重写了func这个方法!");
  15. System.out.println("我是捕获到变量 a == " + a + " 我要么是一个常量,要么是一个没有改变过值的变量!");
  16. }
  17. }.func();
  18. }
  19. }

5.lambda在集合当中的使用

为了能够让 Lambda Java 的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与 Lambda 表达式对接。
对应的接
新增的方法
Collection
removeIf() spliterator() stream() parallelStream() forEach()
List
replaceAll() sort()
Map
getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge()

(1)Collection接口

forEach() 方法演示

该方法在接口 Iterable 当中,原型如下:

  1. default void forEach(Consumer<? super T> action) {
  2. Objects.requireNonNull(action);
  3. for (T t : this) {
  4. action.accept(t);
  5. }
  6. }

该方法表示:对容器中的每个元素执行action指定的动作 。

演示如下: 

  1. package lambdademo;
  2. import java.util.ArrayList;
  3. import java.util.function.Consumer;
  4. public class TestDemo2 {
  5. public static void main(String[] args) {
  6. ArrayList<String> list = new ArrayList<>();
  7. list.add("Hello");
  8. list.add("bit");
  9. list.add("hello");
  10. list.add("lambda");
  11. /*list.forEach(new Consumer<String>(){
  12. @Override
  13. public void accept(String str){ //简单遍历集合中的元素。
  14. System.out.print(str+" ");
  15. }
  16. });*/
  17. //等价于
  18. list.forEach(str -> System.out.print(str + " "));
  19. }
  20. }

(2)List接口

sort() 方法的演示:
sort 方法源码:该方法根据 c 指定的比较规则对容器元素进行排序。
  1. public void sort(Comparator<? super E> c) {
  2. final int expectedModCount = modCount;
  3. Arrays.sort((E[]) elementData, 0, size, c);
  4. if (modCount != expectedModCount) {
  5. throw new ConcurrentModificationException();
  6. }
  7. modCount++;
  8. }

演示如下:

  1. package lambdademo;
  2. import java.util.ArrayList;
  3. import java.util.Comparator;
  4. public class TestDemo2 {
  5. public static void main(String[] args) {
  6. ArrayList<String> list = new ArrayList<>();
  7. list.add("zello");
  8. list.add("bit");
  9. list.add("hello");
  10. list.add("lambda");
  11. list.forEach(str -> System.out.print(str + " "));
  12. System.out.println();
  13. System.out.println("====================");
  14. //list.sort((o1,o2) -> o1.compareTo(o2));
  15. //等价于:
  16. list.sort(new Comparator<String>() {
  17. @Override
  18. public int compare(String o1, String o2) {
  19. return o1.compareTo(o2);
  20. }
  21. });
  22. list.forEach(str -> System.out.print(str + " "));
  23. }
  24. }

编译并运行该代码,输出如下:

 (3)Map接口

HashMap forEach(),该方法原型如下:

 演示如下:

  1. package lambdademo;
  2. import java.util.ArrayList;
  3. import java.util.Comparator;
  4. import java.util.HashMap;
  5. import java.util.function.BiConsumer;
  6. class Test {
  7. public void func(){
  8. System.out.println("func()");
  9. }
  10. }
  11. public class TestDemo2 {
  12. public static void main(String[] args) {
  13. HashMap<Integer, String> map = new HashMap<>();
  14. map.put(1, "hello");
  15. map.put(2, "bit");
  16. map.put(3, "hello");
  17. map.put(4, "lambda");
  18. map.forEach(new BiConsumer<Integer, String>(){
  19. @Override
  20. public void accept(Integer key, String value){
  21. System.out.print(key + "=" + value + " ");
  22. }
  23. });
  24. //简化(使用lambda表达式)
  25. System.out.println();
  26. System.out.println("====================");
  27. map.forEach((k,v)-> System.out.print(k + "=" + v+" "));
  28. }
  29. }
编译并运行该代码,输出如下:

 (6)lambda的优缺点

优点:
代码简洁,开发迅速
②方便函数式编程
③非常容易进行并行计算
④Java 引入 Lambda ,改善了集合操作
缺点:
①代码可读性变差
②在非并行计算中,很多计算未必有传统的 for 性能要高
③不容易进行调试

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/294474
推荐阅读
相关标签
  

闽ICP备14008679号