Java8新特性——Lambda

本文详细介绍 Java 8 的新特性,包括 Lambda 表达式、Stream API 和 Optional 容器类等,以及如何利用这些特性提高代码效率和可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2014年3月发布
公司往往不是追求技术的新,而且追求技术的稳定。所以大多用的之前的版本。

Java 8 新特性简介

    速度更快
        修改底层数据结构:如HashMap(数组-链表-红黑树),HashSet,ConcurrentHashMap(CAS算法)
        修改垃圾回收机制:取消堆中的永久区(PremGen)->回收条件苛刻,使用元空间(MetaSpace)->直接使用物理内存->加载类文件
    代码更少(增加了新的语法Lambda表达式)
    强大的Stream API
    便于并行
    最大化减少空指针异常 Optional容器类

1 Lambda表达式

Lambda是一个匿名函数,可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

public class TestLambda {

    //原来的匿名内部类
    @Test
    public void test1(){
        Comparator<Integer> com=new Comparator<Integer>(){
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        TreeSet<Integer> ts=new TreeSet<>(com);
    }

    //Lambda表达式
    @Test
    public void test2(){
        Comparator<Integer> com=(x,y)->Integer.compare(x,y);
        TreeSet<Integer> ts=new TreeSet<>(com);
    }

    List<Employee> employees=Arrays.asList(
            new Employee("张三",18,9496.2),
            new Employee("李四",52,2396.2),
            new Employee("王五",56,996.2),
            new Employee("赵六",8,94.2)
    );

    @Test
    public void test3(){
        //需求:获取当前公司中员工年龄大于35的员工信息
        List<Employee> emps=filterEmplyees1(employees);
        for(Employee e:emps){
            System.out.println(e);
        }
        System.out.println("---------------------");

        //需求:获取当前公司中员工工资大于2000的员工信息
        List<Employee> emps2=filterEmplyees2(employees);
        for(Employee e:emps2){
            System.out.println(e);
        }
    }

    public List<Employee> filterEmplyees1(List<Employee> list){
        List<Employee> emps=new ArrayList<Employee>();
        for (Employee emp : list) {
            if(emp.getAge()>=35){
                emps.add(emp);
            }
        }
        return emps;
    }

    public List<Employee> filterEmplyees2(List<Employee> list){
        List<Employee> emps=new ArrayList<Employee>();
        for (Employee emp : list) {
            if(emp.getSalary()>=2000){
                emps.add(emp);
            }
        }
        return emps;
    }

    @Test
    public void test4(){
        List<Employee> emps=filterEmplyees(employees,new FilterEmployeeByAge());
        for(Employee e:emps){
            System.out.println(e);
        }
        System.out.println("---------------------");
        List<Employee> emps2=filterEmplyees(employees,new FilterEmployeeBySalary());
        for(Employee e:emps2){
            System.out.println(e);
        }
    }

    //优化方式一:策略设计模式
    public List<Employee> filterEmplyees(List<Employee> list,MyPredicate<Employee> myPredicate){
        List<Employee> emps=new ArrayList<Employee>();
        for (Employee emp : list) {
            if(myPredicate.test(emp)){
                emps.add(emp);
            }
        }
        return emps;
    }

    //优化方式二:匿名内部类
    @Test
    public void test5(){
        List<Employee> list=filterEmplyees(employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee t) {
                return t.getSalary()>=2000;
            }
        });

        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

    //优化方式三:Lambda表达式
    @Test
    public void test6(){
        List<Employee> list=filterEmplyees(employees, (e)->e.getSalary()>=2000);
        list.forEach(System.out::println);
    }

    //优化方式四:stream API
    @Test
    public void test7(){
        employees.stream()
                 .filter((e)->e.getSalary()>=2000)
                 .forEach(System.out::println);

        System.out.println("------------------");

        employees.stream()
                 .map(Employee::getName)
                 .forEach(System.out::println);
    }
}

MyPredicate.java

public interface MyPredicate<T> {
    public boolean test(T t);
}

FilterEmployeeBySalary.java

public class FilterEmployeeBySalary implements MyPredicate<Employee>{
    @Override
    public boolean test(Employee t) {
        return t.getSalary()>=2000;
    }
}

1.1 Lambda表达式的基础语法

Java8中引入了一个新的操作符”->” 该操作符称为箭头操作符或Lambda操作符,箭头操作符将Lambda表达式拆分成两部分:
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需执行的功能,即 Lambda 体

语法格式一:无参数,无返回值 
()->System.out.println(“Hello Lambda!”);

    @Test
    public void test1(){
        //通过匿名内部类的方式实现接口
        Runnable r=new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!");
            }
        };
        r.run();

        System.out.println("----------------------");
        //匿名内部类用代替匿名内部类
        Runnable r1=()->System.out.println("Hello Lambda!");
        r1.run();
    }

语法格式二:有一个参数,并且无返回值
(x)->System.out.println(x);

    @Test
    public void test2(){
        Consumer<String> con=(x)->System.out.println(x);//对Consumer接口中有一个参数的accept方法的实现
        con.accept("啦啦啦");
    }

语法格式三:若只有一个参数,小括号可以不写
 

x->System.out.println(x);

语法格式四:有两个以上的参数,有返回值,并且Lambda体中有多条语句

    @Test
    public void test3(){
        Comparator<Integer> com=(x,y)->{
            System.out.println("函数式接口");
            return Integer.compare(x, y);
        };
    }

语法格式五:若Lambda体中只有一条语句,大括号和 return 都可以省略不写

 @Test
    public void test4(){
        Comparator<Integer> com=(x,y)->Integer.compare(x, y);
    }

语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”

(Integer x,Integer y)->Integer.compare(x,y);

1.2 Lambda表达式需要“函数式接口”的支持

只包含一个抽象方法的接口,称为 函数式接口。

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。

我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接收 Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。
MyFun.java

@FunctionalInterface
public interface MyFun {
    public Integer getValue(Integer num);
}
    //需求:对一个数进行运算
    @Test
    public void  test6(){
        Integer num=operation(100, (x)->x*x);
        System.out.println(num);

        System.out.println(operation(200, (y)->y+200));
    }

    public Integer operation(Integer num,MyFun mf){
        return mf.getValue(num);
    }

1.3 Java提供的内置函数式接口

为了免去用户每次使用Lambda表达式时,都自行创建函数式接口,Java提供了4大核心内置 函数式接口

/**
 * 
 * java内置四大函数式接口
 * 
 * Consumer<T> :消费型接口
 *          void accept(T t);
 * 
 * Supplier<T> :供给型接口
 *          T get();
 * 
 * Function<T,R> :函数型接口
 *          R apply(T t);
 * 
 * Predicate<T> :断言型接口
 *          boolean test(T t);
 *
 */
public class TestLambda3 {

    //Consumer<T> 消费型接口:
    @Test
    public void test1(){
        happy(1000,(m) ->System.out.println("喜欢大宝剑,消费:"+m+"元"));
    }
    public void happy(double money,Consumer<Double> con){
        con.accept(money);
    }

    //Supplier<T> 供给型接口:
    //需求:产生指定个数的整数,并放入集合中
    @Test
    public void test2(){
        List<Integer> numList=getNumList(10, ()->(int)(Math.random()*100));
        for (Integer num : numList) {
            System.out.println(num);
        }
    }
    public List<Integer> getNumList(int num,Supplier<Integer> sup){
        List<Integer> list=new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Integer n=sup.get();
            list.add(n);
        }
        return list;
    }

    //Function<T,R> 函数型接口:
    @Test
    public void test3(){
        String newStr=strHandler("\t\t\t 啦啦啦德玛西亚  ", (str)->str.trim());
        System.out.println(newStr);

        String subStr=strHandler("无与伦比,为杰沉沦", (str)->str.substring(5,9));
        System.out.println(subStr);
    }
    //需求:处理字符串
    public String strHandler(String str,Function<String,String> fun){
        return fun.apply(str);
    }

    //Predicate<T> 断言型接口:
    @Test
    public void test4(){
        List<String> list=Arrays.asList("Hello","jj","Lambda","www","ok");
        List<String> strList=filterStr(list, (s)->s.length()>3);
        for (String string : strList) {
            System.out.println(string);
        }
    }
    //需求:将满足条件的字符串,放入集合中
    public List<String> filterStr(List<String> list,Predicate<String> pre){
        List<String> strList=new ArrayList<>();
        for ( String str : list) {
            if(pre.test(str)){
                strList.add(str);
            }
        }
        return strList;
    }
}

 

1.4 方法引用与构造器引用

/*
 * 一、方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用时Lambda表达式的另一种表现形式)
 * 
 * 主要有三种语法格式:
 * 对象::实例方法名
 * 类::静态方法名
 * 类::实例方法名
 * 
 * 注意:
 * 1、Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
 * 2、若Lambda参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
 * 
 * 
 * 二、构造器引用:
 * 格式:
 * ClassName::new
 * 
 * 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!
 * 
 * 
 * 三:数组引用:
 *  Type::new;
 *  
 */
public class TestMethodRef { 

    //对象::实例方法名
    @Test
    public void test1(){
        PrintStream ps1=System.out;
        Consumer<String> con=(x)->ps1.println(x);//生成了一个实现了Consumer接口的类的对象

        PrintStream ps=System.out;
        Consumer<String> con1=ps::println;//相当于上面,引用了ps对象的println()方法

        Consumer<String> con2=System.out::println;
        con2.accept("abcdef");
    }

    @Test
    public void test2(){
        final Employee emp=new Employee();
        Supplier<String> sup=()->emp.getName();//代替匿名内部类
        String str=sup.get();
        System.out.println(str);

        Supplier<Integer> sup2=emp::getAge;
        Integer num=sup2.get();
        System.out.println(num);
    }

    //类::静态方法名
    @Test
    public void test3(){
        Comparator<Integer> com=(x,y)->Integer.compare(x,y);
        Comparator<Integer> com1=Integer::compare;
    }

    //类::实例方法名
    @Test
    public void test4(){
        BiPredicate<String,String> bp=(x,y)->x.equals(y);
        BiPredicate<String, String> bp2=String::equals;
    }


    //构造器引用
    @Test
    public void test5(){
        Supplier<Employee> sup=()->new Employee();

        //构造器引用方式
        Supplier<Employee> sup2=Employee::new;//使用无参构造器
        Employee emp=sup2.get();
        System.out.println(emp);

        Function<Integer,Employee> fun2=(x)->new Employee(x);
        Employee emp2=fun2.apply(101);
        System.out.println(emp2);

        BiFunction<String,Integer,Employee> bf=Employee::new;
    }

    //数组引用
    @Test
    public void test6(){
        Function<Integer,String[]> fun=(x)->new String[x];
        String[] strs=fun.apply(10);
        System.out.println(strs.length);

        Function<Integer,String[]> fun2=String[]::new;
        String[] str2=fun2.apply(20);
        System.out.println(str2.length);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值