反射枚举及lambda的使用

目录

一、反射

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() 方法
package reflect;

class Student{
    //私有属性name
    private String name = "bit";
    //公有属性age
    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,name)");
    }
    private void eat(){
        System.out.println("i am eat");
    }
    public void sleep(){
        System.out.println("i am a pig");
    }
    private void function(String str) {
        System.out.println(str);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TestDemo2 {
    public static void main(String[] args) throws ClassNotFoundException{
        Class<?> c1 = Class.forName("reflect.Student");

        Class<?> c2 = Student.class;

        Student student = new Student();
        Class<?> c3 = student.getClass();

        System.out.println(c1 == c2);
        System.out.println(c1 == c3);
        System.out.println(c2 == c3);
        //全部都是true,说明不管使用哪种方式获取Class对象,该对象只有一个
    }
}

(7)反射的使用

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

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectClassDemo {
    //通过Class类的newInstance方法获取学生的一个实例
    public static void reflectNewInstance() {
        try{
            Class<?> c1 = Class.forName("reflect.Student");
            Student student = (Student) c1.newInstance();//newInstance()的返回值是T类型
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    // 反射私有或公有的构造方法 屏蔽内容为获得公有的构造方法
    public static void reflectPrivateConstructor() {
        try{
            Class<?> c1 = Class.forName("reflect.Student");
            Constructor<?> constructor = c1.getDeclaredConstructor(String.class, int.class);
            constructor.setAccessible(true);
            Student student = (Student)constructor.newInstance("abc",18);
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    //反射私有属性(获取私有或公开的)
    public static void reflectPrivateField() {
        try {
            Class<?> c1 = Class.forName("reflect.Student");
            Student student = (Student) c1.newInstance();
            Field field = c1.getDeclaredField("name");
            field.setAccessible(true);
            field.set(student,"zhangssan");
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    //反射私有的方法
    public static void reflectPrivateMethod() {
        try {
            Class<?> c1 = Class.forName("reflect.Student");
            Student student = (Student) c1.newInstance();
            Method method = c1.getDeclaredMethod("function", String.class);
            method.setAccessible(true);
            method.invoke(student,"我是私有方法的参数");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        //reflectNewInstance();
        //reflectPrivateConstructor();
        //reflectPrivateField();
        reflectPrivateMethod();
    }
}

五、反射优点和缺点

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

二、枚举

1.背景及定义

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

2.枚举的使用

(1)switch语句里面:

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)常用方法
方法名称描述
values()
以数组形式返回枚举类型的所有成员
ordinal()
获取枚举成员的索引位置
valueOf()
将普通字符串转换为枚举实例
compareTo()
比较两个枚举成员在定义时的顺序
public enum TestEnum {
    RED,BLACK,GREEN,WHITE;

    public static void main(String[] args) {
        TestEnum[] testEnums = TestEnum.values();
        for (int i = 0; i < testEnums.length; i++) {
            System.out.println(testEnums[i] + "-->" + testEnums[i].ordinal());
        }
    }
}
public enum TestEnum {
    RED,BLACK,GREEN,WHITE;

    public static void main(String[] args) {
        TestEnum testEnum = TestEnum.valueOf("RED");//把字符串变成对应的枚举对象
        System.out.println(testEnum);//RED
        System.out.println(RED.compareTo(GREEN));//-2
        System.out.println(BLACK.compareTo(RED));//1
    }
}

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

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

3.枚举的优缺点

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

4.枚举和反射

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

package enumdemo;

public enum TestEnum {
    RED("red",1),BLACK("black",3),GREEN("green",8), WHITE("white",2);

    public String color;
    public int ordinal;
    //构造方法默认是私有的
    TestEnum(String color,int ordinal){
        //super();
        this.color = color;
        this.ordinal = ordinal;
    }
}
package enumdemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestEnumReflect {
    public static void reflectPrivateConstructor(){
        try{
            Class<?> classEnum = Class.forName("enumdemo.TestEnum");
            Constructor<?> declaredConstructorStudent =
                    classEnum.getDeclaredConstructor(String.class,int.class);
            declaredConstructorStudent.setAccessible(true);
            Object objectStudent = declaredConstructorStudent.newInstance("green",666);
            TestEnum testEnum = (TestEnum) objectStudent;
            System.out.println("获得枚举的私有构造函数:"+testEnum);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) {
        reflectPrivateConstructor();
    }
}

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

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

 

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

package enumdemo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class TestEnumReflect {
    public static void reflectPrivateConstructor(){
        try{
            Class<?> classEnum = Class.forName("enumdemo.TestEnum");
            Constructor<?> declaredConstructorStudent =
                    classEnum.getDeclaredConstructor(String.class,int.class,String.class,int.class);
            declaredConstructorStudent.setAccessible(true);
            Object objectStudent = declaredConstructorStudent.newInstance("green",666,"abc",999);
            TestEnum testEnum = (TestEnum) objectStudent;
            System.out.println("获得枚举的私有构造函数:"+testEnum);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) {
        reflectPrivateConstructor();
    }
}

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

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

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

总结:

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

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

5.一条重要的题

写一个单例模式

(1)普通实现

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; 
    } 
}

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

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)); 
    } 
}

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

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表达式

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 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
package lambdademo;

//函数式接口(只有一个抽象方法)
@FunctionalInterface//这个注释修饰这个接口,说明它是函数式接口
interface NoParameterNoReturn{
    void test();
}
public class TestDemo {
    public static void main(String[] args) {
        //简化的写法
        NoParameterNoReturn noParameterNoReturn = () -> System.out.println("重写方法!");
        noParameterNoReturn.test();
    }
    public static void main1(String[] args) {
        NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){
            @Override
            public void test(){
                System.out.println("重写方法!");
            }
        };
        noParameterNoReturn.test();
    }
}

3.基本使用

//没有返回值,没有参数
@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 TestDemo {
    public static void main(String[] args) {
        OneParameterNoReturn oneParameterNoReturn = (a) ->{System.out.println(a);};
        oneParameterNoReturn.test(10);
        //优化
        OneParameterNoReturn oneParameterNoReturn2 = a ->System.out.println(a);
        oneParameterNoReturn.test(10);
        //继续优化
        OneParameterNoReturn oneParameterNoReturn3 = System.out::println;
        oneParameterNoReturn.test(10);

        MoreParameterNoReturn moreParameterNoReturn = (a,b) -> {//理论上来说要写(int a,int b)但是因为a,b同类型,所以两个int都可以省略
            System.out.println(a+b);
        };
        moreParameterNoReturn.test(10,20);

        NoParameterReturn noParameterReturn = () -> {return 10;};
        int ret = noParameterReturn.test();
        System.out.println(ret);
        //简写:
        NoParameterReturn noParameterReturn2 = () -> 10;
        int ret2 = noParameterReturn2.test();
        System.out.println(ret2);

        OneParameterReturn oneParameterReturn = a -> a + 11;
        System.out.println(oneParameterReturn.test(10));

        MoreParameterReturn moreParameterReturn = (a,b) -> a+b;
        System.out.println(moreParameterReturn.test(1,2));
    }
}
Lambda 表达式本质是一个匿名函数,函数的方法是:返回值 方法名 参数列表 方法体。在, Lambda表达式中我们只需要关心参数列表方法体。
语法精简:
①参数类型可以省略,如果需要省略,每个参数的类型都要省略。
②  参数的小括号里面只有一个参数,那么小括号可以省略
③  如果方法体当中只有一句代码,那么大括号可以省略
④  如果方法体中只有一条语句,其是 return 语句,那么大括号可以省略,且去掉 return 关键字。

4.变量捕获

package lambdademo;

class Test {
    public void func(){
        System.out.println("func()");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        int a = 100;
        //a = 99;//error
        new Test() {
            @Override
            public void func() {
                System.out.println("我是内部类,且重写了func这个方法!");
                System.out.println("我是捕获到变量 a == " + a + " 我要么是一个常量,要么是一个没有改变过值的变量!");
            }
        }.func();
    }
}

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 当中,原型如下:

default void forEach(Consumer<? super T> action) { 
    Objects.requireNonNull(action); 
    for (T t : this) { 
        action.accept(t); 
    } 
}

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

演示如下: 

package lambdademo;

import java.util.ArrayList;
import java.util.function.Consumer;

public class TestDemo2 {
    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+" ");
            }
        });*/
        //等价于
        list.forEach(str -> System.out.print(str + " "));
    }
}

(2)List接口

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++; 
}

演示如下:

package lambdademo;

import java.util.ArrayList;
import java.util.Comparator;

public class TestDemo2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("zello");
        list.add("bit");
        list.add("hello");
        list.add("lambda");
        list.forEach(str -> System.out.print(str + " "));
        System.out.println();
        System.out.println("====================");
        //list.sort((o1,o2) -> o1.compareTo(o2));
        //等价于:
        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        list.forEach(str -> System.out.print(str + " "));
    }
}

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

 (3)Map接口

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

 演示如下:

package lambdademo;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.function.BiConsumer;

class Test {
    public void func(){
        System.out.println("func()");
    }
}
public class TestDemo2 {
    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 key, String value){
                System.out.print(key + "=" + value + " ");
            }
        });
        //简化(使用lambda表达式)
        System.out.println();
        System.out.println("====================");
        map.forEach((k,v)-> System.out.print(k + "=" + v+" "));
    }
}
编译并运行该代码,输出如下:

 (6)lambda的优缺点

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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者: (美)Donis Marshall [作译者介绍] 译者: 施平安 王净 蔡兴泉 丛书名: 微软技术丛书 出版社:清华大学出版社 目录回到顶部↑ 第i部分 核心语言. 第1章 visual c#编程简介 3 1.1 visual c# 2008编程示例 4 1.1.1 c#示例程序 4 1.1.2 linq示例程序 6 1.2 visual c# 2008程序的公共要素 8 1.2.1 命名空间 8 1.2.2 main入口点 12 1.2.3 局部变量 13 1.2.4 可空类型 13 1.2.5 表达式 14 1.2.6 选择语句 15 1.2.7 迭代语句 17 1.3 c#核心语言特征 20 1.3.1 符号和标记 20 1.3.2 标识符 36 1.3.3 关键字 36 1.3.4 基元 39 1.4 类型预览 40 第2章 类型 41 .2.1 类 41 2.1.1 类的成员 43 2.1.2 成员函数 48 2.2 结构 67 2.3 枚举 68 2.4 等值与标识 70 2.5 继承预览 71 第3章 继承 72 3.1 继承示例 73 3.2 system.object 76 3.2.1 object.equals方法 77 3.2.2 object.gethashcode方法 78 3.2.3 object.gettype方法 78 3.2.4 object.tostring方法 79 3.2.5 object.memberwiseclone方法 79 3.2.6 object.referenceequals方法 80 3.3 employee类 81 3.4 实现继承 82 3.5 重写继承的行为 83 3.5.1 virtual和override关键字 84 3.5.2 重载与重写 84 3.5.3 重写事件 85 3.5.4 扩展方法 86 3.6 new修饰符 87 3.7 抽象类 90 3.8 密封类 92 3.9 构造函数和析构函数 92 3.10 接口 95 3.10.1 实现接口 97 3.10.2 显式接口成员实现 98 3.10.3 接口的再实现 101 3.11 多态性 103 3.11.1 接口多态性 106 3.11.2 new修饰符和多态性 107 3.12 强制类型转换 108 3.13 属性继承 112 3.14 visual studio 2008预览 113 第ii部分 核心技术 第4章 visual studio 2008简介 117 4.1 迁移到visual studio 2008 117 4.2 集成开发环境 119 4.2.1 起始页 119 4.2.2 创建项目 120 4.2.3 多目标 120 4.2.4 解决方案资源管理器 121 4.2.5 项目类型 123 4.2.6 添加引用 123 4.2.7 visual studio中的窗口管理 124 4.2.8 自动恢复 125 4.3 类层次结构 125 4.3.1 “类视图”窗口 126 4.3.2 对象浏览器 127 4.3.3 类关系图 127 4.3.4 “错误列表”窗口 136 4.4 代码编辑器 137 4.4.1 intellisense 137 4.4.2 外侧代码 138 4.4.3 字体和颜色格式化 138 4.4.4 源代码格式设置 139 4.4.5 修改跟踪 139 4.5 代码段 140 4.5.1 插入代码段 140 4.5.2 默认的代码段 142 4.5.3 代码段管理器 143 4.5.4 创建代码段 144 4.5.5 复制和粘贴 149 4.6 重构 149 4.7 生成和部署 153 4.7.1 msbuild 154 4.7.2 clickonce部署 158 4.8 数组和集合预览 163 第5章 数组和集合 165 5.1 数组 167 5.1.1 数组元素 168 5.1.2 多维数组 169 5.1.3 交错数组 171 5.1.4 system.array 172 5.1.5 system.array属性 179 5.1.6 params关键字 185 5.1.7 数组转换 187 5.2 集合 188 5.2.1 arraylist集合 189 5.2.2 bitarray集合 192 5.2.3 hashtable集合 194 5.2.4 queue集合 198 5.2.5 sortedlist 199 5.2.6 stack集合 202 5.2.7 专用集合 203 5.3 linq预览 204 第6章 linq简介 205 6.1 c#扩展 206 6.1.1 类型推断 206 6.1.2 对象初始值设定项 207 6.1.3 匿名类型 207 6.1.4 扩展方法 208 6.1.5 lambda表达式 208 6.1.6 表达式目录树 209 6.2 linq基础 210 6.2.1 核心要素 210 6.2.2 转换运算符 213 6.2.3 linq查询表达式语法 214 6.2.4 linq在哪里 215 6.3 linq to objects 216 6.4 linq运算符 219 6.4.1 聚合运算符 219 6.4.2 连接运算符 220 6.4.3 数据类型转换运算符 220 6.4.4 元素运算符 222 6.4.5 等于运算符 223 6.4.6 筛选运算符 223 6.4.7 生成运算符 223 6.4.8 分组运算符 224 6.4.9 联接运算符 224 6.4.10 分区运算符 225 6.4.11 量词运算符 226 6.4.12 集合运算符 226 6.4.13 排序运算符 227 6.5 泛型预览 228 第7章 泛型 229 7.1 泛型类型 231 7.1.1 类型形参 232 7.1.2 类型实参 232 7.1.3 构造类型 235 7.1.4 重载方法 236 7.2 泛型方法 237 泛型类型的this引用 238 7.3 约束 238 7.3.1 派生约束 239 7.3.2 接口约束 243 7.3.3 值类型约束 244 7.3.4 引用类型约束 245 7.3.5 默认的构造函数约束 246 7.4 强制类型转换 246 7.5 继承 247 7.5.1 重写泛型方法 248 7.5.2 嵌套类型 249 7.6 静态成员 250 7.6.1 运算符函数 251 7.6.2 序列化 252 7.6.3 泛型本质 254 7.6.4 泛型集合 255 7.7 枚举器预览 256 第8章 枚举器 257 8.1 可枚举的对象 258 8.1.1 枚举器 258 8.1.2 枚举器实例 260 8.1.3 枚举器实例(版本化集合) 261 8.1.4 ienumerator问题 263 8.2 泛型枚举器 263 8.2.1 ienumerable[t]接口 264 8.2.2 ienumerator[t]接口 264 8.2.3 泛型枚举器实例(版本化集合) 265 8.3 迭代器 267 8.4 运算符重载预览 274 第iii部分 c#语言详解 第9章 运算符重载 277 9.1 数学运算符和逻辑运算符 278 9.1.1 实现 279 9.1.2 自增和自减运算符 281 9.1.3 左移和右移运算符.. 282 9.1.4 true和false运算符 283 9.1.5 成对运算符 284 9.2 转换运算符 288 9.3 实例 291 9.4 运算符重载的本质 294 9.5 委托和事件预览 296 第10章 委托和事件 297 10.1 委托 297 10.1.1 定义委托 298 10.1.2 创建委托 299 10.1.3 逆变和协变 300 10.1.4 激活委托 300 10.1.5 委托数组 301 10.1.6 system.multicastdelegate类 302 10.1.7 调用列表 303 10.1.8 泛型和委托 306 10.1.9 异步调用 307 10.1.10 异步委托图 310 10.1.11 异常 311 10.2 匿名方法 312 10.2.1 外部变量 314 10.2.2 泛型匿名方法 316 10.2.3 匿名方法的局限性 316 10.3 事件 317 10.3.1 发布事件 317 10.3.2 订阅者 318 10.3.3 引发事件 318 10.4 linq编程预览 320 第11章 linq编程 321 11.1 linq to xml 321 11.1.1 xml架构 322 11.1.2 验证 322 11.1.3 导航 323 11.1.4 显式的强制类型转换 327 11.1.5 xml修改 328 11.1.6 xml查询表达式 330 11.2 linq to sql 331 11.2.1 实体类 331 11.2.2 linq to sql查询表达式 333 11.2.3 linq to dataset 334 11.2.4 关联 335 11.2.5 linq to sql更新 337 11.3 异常处理预览 339 第12章 异常处理 340 12.1 异常示例 340 12.2 标准异常模型 341 12.3 结构化异常处理 342 12.3.1 try语句 342 12.3.2 catch语句 343 12.3.3 异常的传播 344 12.3.4 finally语句 346 12.3.5 异常信息表 346 12.3.6 嵌套的try块 347 12.4 system.exception 348 12.4.1 system.exception函数 349 12.4.2 system.exception属性 350 12.4.3 应用程序异常 351 12.4.4 异常转换 353 12.4.5 com互操作性异常 353 12.5 远程异常 357 12.6 未处理的异常 358 12.6.1 application.threadexception 360 12.6.2 appdomain.unhandledexception 360 12.7 在visual studio中管理异常 361 12.7.1 异常助手 362 12.7.2 “异常”对话框 362 12.8 元数据和反射预览 363 第iv部分 调试 第13章 元数据和反射 367 13.1 元数据 367 13.1.1 元数据标记 369 13.1.2 元数据堆 369 13.1.3 流 370 13.1.4 元数据验证 370 13.1.5 ildasm 371 13.2 反射 375 13.2.1 获得type对象 376 13.2.2 加载程序集 378 13.2.3 浏览类型信息 380 13.2.4 动态调用 383 13.2.5 类型的创建 387 13.2.6 晚期绑定委托 389 13.2.7 函数调用性能 391 13.3 反射和泛型 391 13.3.1 isgeneric和isgenerictypedefinition 392 13.3.2 typeof 393 13.3.3 gettype 393 13.3.4 getgenerictypedefinition 394 13.3.5 getgenericarguments 394 13.3.6 创建泛型类型 395 13.3.7 反射的安全性 396 13.3.8 属性 397 13.3.9 程序员定义的自定义属性 399 13.3.10 属性和反射 403 13.4 msil预览 405 第14章 msil编程 406 14.1 “hello world”应用程序 408 14.2 计算堆栈 409 14.3 msil详解 410 14.4 复杂任务 419 14.5 分支 424 14.6 数组 428 14.7 算术指令 430 14.8 转换运算 430 14.9 异常处理 431 14.10 其他操作 432 14.11 进程执行 432 14.12 用visual studio 2008进行调试预览 436 第15章 用visual studio 2008进行调试 437 15.1 调试概述 438 15.1.1 调试windows窗体项目 438 15.1.2 附加到运行进程 438 15.1.3 调试控制台应用程序项目 440 15.1.4 调试类库项目 440 15.2 调试配置 441 15.2.1 debug和release配置 441 15.2.2 配置管理器 441 15.3 调试设置 442 15.3.1 visual studio环境调试设置 442 15.3.2 解决方案的调试设置 447 15.3.3 项目的调试设置 448 15.4 断点 449 15.4.1 函数断点 449 15.4.2 “断点”窗口 450 15.4.3 跟踪点 454 15.5 代码逐步调试 456 15.5.1 逐步调试命令 456 15.5.2 “设置下一条语句”实例 456 15.6 “调试”工具栏 457 15.7 数据提示 458 15.8 调试窗口 460 15.8.1 “断点”窗口 460 15.8.2 “输出”窗口 460 15.8.3 “监视”窗口和其他变量窗口 461 15.8.4 自动窗口 463 15.8.5 “局部变量”窗口 463 15.8.6 “即时”窗口 463 15.8.7 “调用堆栈”窗口 466 15.8.8 “线程”窗口 467 15.8.9 “模块”窗口 468 15.8.10 “进程”窗口 468 15.8.11 “内存”窗口 469 15.8.12 “反汇编”窗口 469 15.8.13 “寄存器”窗口 470 15.9 跟踪 471 15.9.1 跟踪实例 478 15.9.2 配置文件 481 15.9.3 使用配置文件进行跟踪的示例 482 15.10 debuggerdisplayattribute 484 15.11 debuggerbrowsableattribute 486 15.12 debuggertypeproxyattribute 488 15.13 转储文件 488 15.14 高级调试预览 490 第16章 高级调试 491 16.1 debuggableattribute属性 492 16.2 调试器 493 16.3 托管调试器(mdbg) 493 16.3.1 mdbg实例 494 16.3.2 mdbg命令 497 16.4 windbg 499 16.5 son of strike(sos) 505 16.5.1 sos实例——第1部分 506 16.5.2 sos实例——第2部分 508 16.6 转储文件 510 16.7 内存管理 512 16.7.1 对象图 513 16.7.2 代 515 16.7.3 终结进程 519 16.7.4 可靠性和性能监视器 519 16.8 线程 520 16.9 异常 526 16.10 符号 527 16.10.1 symsrv符号服务器 528 16.10.2 应用程序符号 529 16.11 内存管理预览 529 第v部分 高级特性 第17章 内存管理 533 17.1 非托管资源 534 17.1.1 垃圾回收概述 535 17.1.2 gc风格 538 17.2 终结器 539 17.3 idisposable.dispose 551 17.3.1 disposable模式 554 17.3.2 disposable模式的考虑因素 555 17.4 弱引用 560 17.4.1 弱引用内部机理 562 17.4.2 weakreference类 563 17.4.3 可靠的代码 563 17.4.4 管理非托管资源 566 17.5 gc类 569 17.6 不安全的代码预览 569 第18章 不安全的代码 570 18.1 unsafe关键字 572 18.1.1 指针 573 18.1.2 指针参数和指针返回值 575 18.1.3 p/invoke 578 18.2 小结 590 索引... 591

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值