Java的反射(reflection)机制是在**运行**时检查、访问和修改类、接口、字段和方法的机制;这种动态 获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

Class帮助文档代表类的实体,在**运行**的Java应用程序中表示类和接口。 Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件,被编译后的Java文件.class也被JVM解析为一个对象,这个对象就是java.lang.Class。这样当程序在运行时,每个java文件就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类。

getClassLoaded() 有三个类的加速器,这个是看是哪个加速去




在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意⼀个类,都能够知道这个类的所有属性和方法;对于任意⼀个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息。 第⼀种,使用 Class.forName("类的全路径名");静态方法。 前提:已明确类的全路径名。 第二种,使用.class方法。 说明:仅适合在编译前就已经明确要操作的Class 第三种,使用类对象的getClass()方法

和普通的类不一样,一个类只有一个class,和类是对应的
newInstance() 方法的作用是创建对应类的一个新实例(对象)。
具体来说:
Class 类的一个方法,调用时会调用对应类的无参构造方法来创建对象。

String.class 表示获取 String 类的字节码对象(Class<String> 类型);<?> ... 可变参数

把这个保险打开 setAccessible()
class Student {
// 私有属性
private String name = "bit";
// 公有属性
public int age = 18;
// 不带参数的构造方法
public Student() {
System.out.println("Student()");
}
// 私有构造方法
private Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Student(String, int)");
}
// 私有方法
private void eat() {
System.out.println("i am eat");
}
// 公有方法
public void sleep() {
System.out.println("i am pig");
}
// 带参数的私有方法
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class TestDemo {
public static void main(String[] args) {
/*
1. 通过 getClass() 方法获取 Class 对象
*/
Student s1 = new Student();
Class c1 = s1.getClass();
/*
2. 直接通过 类名.class 方式获取
该方法安全可靠,程序性能更高,任何类都有隐含的静态成员变量 class
*/
Class c2 = Student.class;
/*
3. 通过 Class 类的 forName() 静态方法获取(最常用)
需传入类的全路径(含包名,此处无包则直接写类名)
可能抛出 ClassNotFoundException 异常
*/
Class c3 = null;
try {
c3 = Class.forName("Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 验证:一个类在 JVM 中只有一个 Class 实例,三者相等
System.out.println(c1.equals(c2)); // true
System.out.println(c1.equals(c3)); // true
System.out.println(c2.equals(c3)); // true
}
}三种方法都在下面的使用中了
接下来我们开始使用反射,我们依旧反射上面的Student类,把反射的逻辑写到另外的类当中进行理解
注意:所有和反射相关的包都在 import java.lang.reflect 包下面。
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java java.lang.reflect.Method;
public class ReflectClassDemo {
// 反射创建对象(使用无参构造方法)
public static void reflectNewInstance() {
try {
// 获取Student类的Class对象
Class<?> classStudent = Class.forName("Student");
// 通过无参构造方法创建实例(需类有public无参构造)
Object objectStudent = classStudent.newInstance();
Student student = (Student) objectStudent;
System.out.println("获得学生对象:" + student);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射访问私有构造方法
public static void reflectPrivateConstructor() {
try {
Class<?> classStudent = Class.forName("Student");
// 获取私有构造方法(参数为String和int类型)
Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class, int.class);
// 突破访问权限(私有成员需设置为可访问)
declaredConstructorStudent.setAccessible(true);
// 通过私有构造方法创建实例并传参
Object objectStudent = declaredConstructorStudent.newInstance("高博", 15);
Student student = (Student) objectStudent;
System.out.println("获得私有构造方法创建的对象(修改姓名和年龄):" + student);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射访问并修改私有属性
public static void reflectPrivateField() {
try {
Class<?> classStudent = Class.forName("Student");
// 获取私有属性name
Field field = classStudent.getDeclaredField("name");
// 突破访问权限
field.setAccessible(true);
// 创建实例(使用无参构造)
Object objectStudent = classStudent.newInstance();
Student student = (Student) objectStudent;
// 修改私有属性值
field.set(student, "小明");
// 获取修改后的属性值
String name = (String) field.get(student);
System.out.println("反射私有属性修改了name:" + name);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 反射访问私有方法
public static void reflectPrivateMethod() {
try {
Class<?> classStudent = Class.forName("Student");
// 获取私有方法function(参数为String类型)
Method methodStudent = classStudent.getDeclaredMethod("function", String.class);
System.out.println("私有方法的方法名为:" + methodStudent.getName());
// 突破访问权限
methodStudent.setAccessible(true);
// 创建实例
Object objectStudent = classStudent.newInstance();
Student student = (Student) objectStudent;
// 调用私有方法并传参
methodStudent.invoke(student, "我是给私有的function函数传的参数");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
// 可根据需要取消注释测试不同反射功能
// reflectNewInstance(); // 测试反射创建对象
// reflectPrivateConstructor(); // 测试反射私有构造方法
// reflectPrivateField(); // 测试反射私有属性
reflectPrivateMethod(); // 测试反射私有方法
}
}Class 类、Field 类、Method 类、Constructor 类。枚举是在JDK1.5以后引入的。主要用途是:将⼀组常量组织起来,在这之前表示⼀组常量通常使用定义常量的方式:
public static final int RED = 1;
public static final int GREEN = 2;
public static final int BLACK = 3;但是常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以 直接用枚举来进行组织,这样⼀来,就拥有了类型,枚举类型。而不是普通的整形 1
public enum TestEnum {
RED,BLACK,GREEN;
}优点:将常量组织起来统⼀进行管理
场景:错误状态码,消息类型,颜色的划分,状态机等等....
本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但 是其默认继承了这个类。
public 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;
}
}
}2.常用方法
Enum 类的常用方法

示例一:
public enum TestEnum {
RED,BLACK,GREEN,WHITE;
public static void main(String[] args) {
TestEnum[] testEnum2 = TestEnum.values();
for (int i = 0; i < testEnum2.length; i++) {
System.out.println(testEnum2[i] + " " + testEnum2[i].ordinal());
}
System.out.println("=========================");
System.out.println(TestEnum.valueOf("GREEN"));
}
}示例二
public 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))刚刚说过,在Java当中枚举实际上就是⼀个类。所以我们在定义枚举的时候,还可以这样定义和使用 枚举
public enum TestEnum {
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 TestEnum (String name,int key) {
this.name = name;
this.key = key;
}
public static TestEnum getEnumKey (int key) {
for (TestEnum t: TestEnum.values()) {
if(t.key == key) {
return t;
}
}
return null;
}
public static void main(String[] args) {
System.out.println(getEnumKey(2));
}
}1. 枚举常量更简单安全。
2. 枚举具有内置方法,代码更优雅
1. 不可继承,无法扩展

Java 编译器在处理枚举类(如TestEnum)时,会自动为其隐式生成values()方法。这个方法并非从父类Enum继承而来,而是编译器针对枚举类型的特殊 “语法糖” 实现。
values()方法的核心作用是返回当前枚举类中所有枚举常量的数组。例如在代码中,TestEnum.values()会返回一个包含TestEnum所有枚举实例的TestEnum[]数组,从而支持遍历、统计等操作。
我们刚刚在反射里面看到了,任何⼀个类,哪怕其构造方法是私有的,我们也可以通过反射拿到他的实例对象,那么枚举的构造方法也是私有的,我们是否可以拿到呢?接下来,我们来实验⼀下: 同样利用上述提供的枚举类来进行举例:
public enum TestEnum {
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 TestEnum(String name, int key) {
this.name = name;
this.key = key;
}
public static TestEnum getEnumKey(int key) {
for (TestEnum t : TestEnum.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();
}
}
public static void main(String[] args) {
reflectPrivateConstructor();
}
}输出结果:
java.lang.NoSuchMethodException: TestEnum.<init>(java.lang.String, int)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at TestEnum.reflectPrivateConstructor(TestEnum.java:40)
at TestEnum.main(TestEnum.java:54)我们提供的枚举的构造方法就是两个参数分别是 String 和 int ,这里的异常信息是 java.lang.NoSuchMethodException: TestEnum.(java.lang.String, int) 枚举比较特殊,虽然我们写的是两个,但是默认他还添加了两个参数,哪两个参数呢?我们看⼀ 下Enum类的源码
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}也就是说,我们自己的构造函数有两个参数⼀个是String⼀个是int,同时他默认还会给两个参数,⼀ 个是String⼀个是int。也就是说,这里我们正确给的是4个参数:
public static void reflectPrivateConstructor() {
try {
Class<?> classStudent = Class.forName("TestEnum");
//注意传⼊对应的参数,获得对应的构造⽅法来构造对象,当前枚举类是提供了两个参数分别String和int。
Constructor<?> declaredConstructorStudent =
classStudent.getDeclaredConstructor(String.class,int.class,String.class,int.cla
ss);
//设置为true后可修改访问权限
declaredConstructorStudent.setAccessible(true);
//后两个为⼦类参数,⼤家可以将当前枚举类的key类型改为double验证
Object objectStudent = declaredConstructorStudent.newInstance("⽗类参数",666,"⼦类参数",888);
TestEnum testEnum = (TestEnum) objectStudent;
System.out.println("获得枚举的私有构造函数:"+testEnum);
} catch (Exception ex) {
ex.printStackTrace();
}
}此时运行程序结果是:
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:416)
at TestEnum.reflectPrivateConstructor(TestEnum.java:46)
at TestEnum.main(TestEnum.java:55)这次就是我想要的结果!此时的异常信息显示,是我的⼀个方法这个方法是 newInstance() 报错问题就是这里,我们来看⼀下这个方法的源码,为什么会抛出 java.lang.IllegalArgumentException: 异常呢? 源码显示 newInstance() 报错
是的,枚举在这里被过滤了,你不能通过反射获取枚举类的实例!这道题是2017年阿里巴巴曾经问到 的⼀个问题,不看不知道,⼀看吓⼀跳!同学们记住这个坑。原版问题是:为什么枚举实现单例模式 是安全的?希望同学们记住这个问题!

Constructor.newInstance()创建枚举实例时,会触发IllegalArgumentException(因为枚举的构造方法被编译器特殊处理,反射创建会被明确禁止)。Java 的Enum类的构造方法被设计为只能由 JVM 调用,且反射框架在检测到要创建枚举实例时,会主动抛出异常。例如,当你通过反射获取枚举的构造方法并尝试调用newInstance()时,会触发IllegalArgumentException,明确禁止这种操作。
如果你是枚举
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class){
if(uniqueInstance == null){//进⼊区域后,再检查⼀次,如果仍是null,才创建实例
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}class Singleton {
/**
私有化构造器
*/
private Singleton() {
}
/**
对外提供公共的访问⽅法
*/
public static Singleton getInstance() {
return UserSingletonHolder.INSTANCE;
}
/**
写⼀个静态内部类,⾥⾯实例化外部类
*/
private static class UserSingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
public class Main {
public static void main(String[] args) {
Singleton u1 = Singleton.getInstance();
Singleton u2 = Singleton.getInstance();
System.out.println("
两个实例是否相同:
"+ (u1==u2));
}
}public enum TestEnum {
INSTANCE;
public TestEnum getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
TestEnum singleton1=TestEnum.INSTANCE;
TestEnum singleton2=TestEnum.INSTANCE;
System.out.println("两个实例是否相同:"+(singleton1==singleton2));
}
}Lambda表达式是JavaSE8中⼀个重要的新特性。lambda表达式允许你通过表达式来代替功能接 口。lambda表达式就和⽅法⼀样,它提供了⼀个正常的参数列表和⼀个使用这些参数的主体(body,可 以是⼀个表达式或⼀个代码块)。Lambda表达式(Lambdaexpression),基于数学中的λ演算得 名,也可称为闭包(Closure)。
基本语法 : (parameters ) ->expression 或(parameters) -> {statements;}
Lambda表达式由三部分组成:
1. paramaters:类似方法中的形参列表,这⾥的参数是函数式接口里的参数。这⾥的参数类型可以 明确的声明也可不声明⽽由JVM隐含的推断。另外当只有⼀个推断类型时可以省略掉圆括号。 2.-> :可理解为“被用于”的意思
3. 方法体:可以是表达式也可以代码块,是函数式接口里的方法的实现。代码块可返回⼀个值或者什么 都不反回,这⾥的代码块块等同于方法的方法体。如果是表达式,也可以返回⼀个值或者什么都不返回

要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:
⼀个接口有且只有⼀个抽象方法。
注意:
1. 如果⼀个接口只有⼀个抽象方法,那么该接口就是⼀个函数式接口
2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接 ⼝的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来 说,只要你保证你的接口中只有⼀个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有⼀个⽅法
void test();
}但是这种方式也是可以的:
@FunctionalInterface
interface NoParameterNoReturn {
void test();
default void test2() {
}
}
System.out.println("JDK1.8新特性,default默认⽅法可以有具体的实现");首先,我们事先准备好好几个接口:
//无返回值无参数
@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);
}我们在上面提到过,Lambda可以理解为:Lambda就是匿名内部类的简化,实际上是创建了⼀个类, 实现了接口,重写了接口的方法。
没有使用lambda表达式的时候的调用方式:
NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){
@Override
public void test() {
System.out.println("hello");
}
};
noParameterNoReturn.test();具体使用见以下示例代码:
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);
}
}1.参数类型可以省略,如果需要省略,每个参数的类型都要省略。
2.参数的小括号里面只有⼀个参数,那么小括号可以省略
3.如果方法体当中只有⼀句代码,那么大括号可以省略
4.如果方法体中只有⼀条语句,且是return语句,那么大括号可以省略,且去掉return关键字。
示例代码:
public static void main(String[] args) {
// 无返回值多个参数,省略参数类型
MoreParameterNoReturn moreParameterNoReturn = (a, b) -> {
System.out.println("无返回值多个参数,省略参数类型:" + a + " " + b);
};
moreParameterNoReturn.test(20, 30);
// 无返回值一个参数,小括号可省略
OneParameterNoReturn oneParameterNoReturn = a -> {
System.out.println("无返回值一个参数,小括号可省略:" + a);
};
oneParameterNoReturn.test(10);
// 无参数无返回值,方法体只有一行代码(省略大括号)
NoParameterNoReturn noParameterNoReturn = () -> System.out.println("无参数无返回值,方法体中只有一行代码");
noParameterNoReturn.test();
// 方法体只有一条return语句,省略return和大括号
NoParameterReturn noParameterReturn = () -> 40;
int ret = noParameterReturn.test();
System.out.println(ret);
}Lambda表达式中存在变量捕获,了解了变量捕获之后,我们才能更好的理解Lambda表达式的左右域。Java当中的匿名类中,会存在变量捕获。
匿名内部类就是没有名字的内部类。我们这里只是为了说明变量捕获,所以,匿名内部类只要会使用就好,那么下面我们来,简单的看看匿名内部类的使用就好了。 具体想详细了解的同学戳这里:匿名内部类我们通过简单的代码来学习⼀下
class Test {
public void func(){
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
new Test(){
@Override
public void func() {
System.out.println("我是内部类,且重写了func这个⽅法!");
}
};
}
}在上述代码当中的main函数当中,我们看到的就是⼀个匿名内部类的简单的使用
class Test {
public void func(){
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test(){
@Override
public void func() {
System.out.println("我是内部类,且重写了func这个⽅法!"); System.out.println("我是捕获到变量 a == "+a
+" 我是⼀个常量,或者是⼀个没有改变过值的变量!");
}
};
}
}在上述代码当中的变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的你 要保证在使用之前,没有修改。如下代码就是错误的代码。
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test() {
@Override
public void func() {
a = 99;
System.out.println("我是内部类,且重写了func这个方法!");
System.out.println("我是捕获到变量 a = " + a
+ " 我是一个常量,或者是一个没有改变过值的变量!");
}
};
}
}该代码直接编译报错
在Lambda当中也可以进⾏变量的捕获,具体我们看⼀下代码
@FunctionalInterface
interface NoParameterNoReturn {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99; error
System.out.println("捕获变量: "+a);
};
noParameterNoReturn.test();
}为了能够让Lambda和Java的集合类集更好的⼀起使⽤,集合当中,也新增了部分接⼝,以便与 Lambda表达式对接。

以上方法的作用可自行查看我们发的帮助手册。我们这里会示例⼀些方法的使用。
注意:Collection的 forEach()方法是从接口 java.lang.Iterable 拿过来的。
for Each() 方法演示 该方法在接口 Iterable 当中,原型如下
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}该方法表示:对容器中的每个元素执行action指定的动作。
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+" ");
}
});
}输出结果:Hello bit hello lambda
我们可以修改为如下代码:
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);
});
}输出结果:Hello bit hello lambda
sort()方式的演示
sort方法源码:该方法根据c指定的比较规则对容器元素进行排序。
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}使用示例:
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);输出结果:bit,Hello,hello,lambda
修改为lambda表达式:
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);
}输出结果:bit,Hello,hello,lambda
HashMap 的 forEach() 该方法原型如下:
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}作⽤是对Map中的每个映射执执行action指定的操作。
代码示例:
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "bit");
map.put(3, "hello");
map.put(4, "lambda");
map.forEach(new BiConsumer<Integer, String>(){
@Override
public void accept(Integer k, String v){
System.out.println(k + "=" + v);
}
});
}输出结果:
1=hello
2=bit
3=hello
4=lambda
使用lambda表达式后的代码:
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "hello");
map.put(2, "bit");
map.put(3, "hello");
map.put(4, "lambda");
map.forEach((k,v)-> System.out.println(k + "=" + v));
}输出结果:
1=hello
2=bit
3=hello
4=lambda
Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
1. 代码简洁,开发迅速
2. 方便函数式编程
3. 非常容易进行并行计算
4. Java引入Lambda,改善了集合操作
1. 代码可读性变差
2. 在非并行计算中,很多计算未必有传统的for性能要高
3. 不容易进行调试