java8新特性之lambda表达式

java8新特性简介

  • 速度更快,修改了一些底层的数据结构和内存模型。比如说HashMap。在JDK7之前,采用的是数组+链表的数据结构,到jdk8之后改为数组+链表+红黑树,这是数据结构的修改。再比如说,取消永久代,改为元空间,这是内存模型的更改
  • 代码更少,增加了lambda表达式
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常

lambda表达式

1、为什么要使用lambda表达式

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

2、入门小案例

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>java8</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
    </dependencies>
</project>
  • TestLambda.java类
package com.xuzhi.lambda;

import com.xuzhi.entity.Employee;
import com.xuzhi.predicate.FilterEmployeeByAge;
import com.xuzhi.predicate.FilterEmployeeBySalary;
import com.xuzhi.predicate.MyPredicate;
import org.junit.Test;

import java.util.*;

/**
 * Author: 徐志
 * Date: 2020/8/1 9:58
 */
public class TestLambda {

    /**
     * 使用匿名内部类来实现
     */
    @Test
    public void test1() {
        Comparator<Integer> com = new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        TreeSet<Integer> ts=new TreeSet<Integer>(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,9999.99),
            new Employee("李四",38,5555.99),
            new Employee("王五",50,6666.99),
            new Employee("赵六",16,3333.99),
            new Employee("田七",8,7777.99)
    );


    //需求:获取年龄大于34的员工信息,使用传统方式
    public List<Employee> filterEmployee1(List<Employee> list){
        List<Employee> emps=new ArrayList<>();
        for (Employee emp:list) {
            if (emp.getAge()>34){
                emps.add(emp);
            }
        }
        return emps;
    }

    @Test
    public void test3(){
        List<Employee> list=filterEmployee1(employees);

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

    //需求:获取工资大于5000的员工信息,使用传统方式
    public List<Employee> filterEmployee2(List<Employee> list){
        List<Employee> emps=new ArrayList<>();

        for (Employee emp:list) {
            if (emp.getSalary()>5000){
                emps.add(emp);
            }

        }
        return emps;
    }

    @Test
    public void test4(){
        List<Employee> list=filterEmployee2(employees);

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

/** -------------------------------------------------------分割线---------------------------------------------------------------**/
    public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp){
        List<Employee> emps=new ArrayList<>();

        for (Employee employee:list) {
            if(mp.test(employee)){
                emps.add(employee);
            }

        }
        return emps;
    }

    
   /**优化方式一:使用该策略设计模式,创建一个接口,根据不同的需求来实现这个接口,缺点是当需求增加了,类的数量也在增加
   */
    @Test
    public void test5(){
        List<Employee> list=filterEmployee(employees,new FilterEmployeeByAge());
        for (Employee employee:list){
            System.out.println(employee);
        }
        System.out.println("----------------------");

        List<Employee> list2=filterEmployee(employees,new FilterEmployeeBySalary());
        for (Employee employee:list2){
            System.out.println(employee);
        }
    }

    //优化方式二:使用匿名内部类来实现接口
    public void test6(){
        List<Employee> list=filterEmployee(employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary()<5000;
            }
        });

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

    //使用lambda表达式
    @Test
    public void test7(){
        List<Employee> list=filterEmployee(employees,(e)->e.getSalary()<5000);
        list.forEach(System.out::println);
    }

    //使用stream API
    @Test
    public void test8(){
        employees.stream()
                .filter((e)->e.getSalary()>=5000)
                .forEach(System.out::println);
    }
}

  • Employee.java实体类
package com.xuzhi.entity;

import lombok.*;

/**
 * Author: 徐志
 * Date: 2020/8/1 10:10
 */

@Setter
@Getter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    private String name;
    private int age;
    private double salary;
}

  • MyPredicate.java
package com.xuzhi.predicate;

/**
 * Author: 徐志
 * Date: 2020/8/1 10:37
 */
public interface MyPredicate<T> {
    public boolean test(T t);
}

  • FilterEmployeeByAge.java类
package com.xuzhi.predicate;

import com.xuzhi.entity.Employee;

/**
 * Author: 徐志
 * Date: 2020/8/1 10:39
 */
public class FilterEmployeeByAge implements MyPredicate<Employee> {
    @Override
    public boolean test(Employee employee) {
        return employee.getAge()>34;
    }
}

  • FilterEmployeeBySalary.java
package com.xuzhi.predicate;

import com.xuzhi.entity.Employee;

/**
 * Author: 徐志
 * Date: 2020/8/1 10:38
 */
public class FilterEmployeeBySalary implements MyPredicate<Employee> {

    @Override
    public boolean test(Employee employee) {
        return employee.getSalary()>5000;
    }
}

3、lambda表达式基础语法

  • lambda的基本语法:“->”该操作符称为箭头操作符或lambda操作符,箭头操作符将表达式拆为两部分
  • 左侧: lambda表达式需要的参数列表,即接口中抽象方法的参数列表
  • 右侧: lambda表达式所需执行的功能
  • lambda表达式参数类型可以不写
  • lambada表达式需要函数式接口支持
  • 函数式接口:接口里面只有一个抽象方法,可以使用@FuncutionalInterface注解修饰检查接口是否为函数式接口
package com.xuzhi.lambda;

/**
 * Author: 徐志
 * Date: 2020/8/1 11:10
 */

import com.xuzhi.function.MyFunction;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;

public class TestLambda2 {

   //使用匿名内部类
    @Test
    public void test1(){
        Runnable r=new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        System.out.println("----------------------------------------------------");

        /*
        语法一:无参数无返回值
         */
        Runnable r1=()-> System.out.println("hello lambda");

    }

    @Test
    public void test2(){
        /*
         语法二:有一个参数无返回值
         */
        Consumer<String> con=(x)->System.out.println(x);
        con.accept("笨蛋");

    }


    @Test
    public void test3(){
        /*
        语法三:两个参数,有返回值,多条语句
         */
        Comparator<Integer> com=(x,y)->{
            System.out.println("hello");
            return Integer.compare(x,y);
        };

        /*
         语法四:两个参数,有返回值,一条语句
         */
        Comparator<Integer> com2=(x,y)-> Integer.compare(x,y);

    }

    //需求:对一个数进行操作
    @Test
    public void test4(){
        Integer result= operation(100,(x)->x*x);
        System.out.println(result);

        System.out.println(operation(100,(x)->x+x));

    }

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

4、四大函数式接口

  • 消费型接口:有参数无返回值
  • 供给型接口:无参数有返回值
  • 函数型接口:有参数有返回值
  • 断定型接口:有参数返回值为布尔
package com.xuzhi.lambda;

/**
 * Author: 徐志
 * Date: 2020/8/1 13:55
 */

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * 四大核心函数式接口
 *
 * 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 {

    //消费型接口
    @Test
    public void test1(){
        happy(1000,(m)-> System.out.println("消费了"+m));

    }

    public void happy(double money, Consumer<Double> con){
        con.accept(money);
    }

    //供给型接口
    @Test
    public void test2(){
        List<Integer> numList = getNumList(10, () -> (int) Math.random() * 100);

        for (Integer n:numList) {
            System.out.println(n);
        }

    }

    public List<Integer> getNumList(int num, Supplier<Integer> sup){
        List<Integer> list=new ArrayList<>();
        for (int i=0;i<num;i++){
            Integer integer = sup.get();
            list.add(integer);
        }
        return list;
    }

    //函数型接口
    @Test
    public void test3(){
        String s = strHandeler("aaa", (x) -> x.toUpperCase());
        System.out.println(s);
    }

    public String strHandeler(String str, Function<String,String> fun){
        return fun.apply(str);
    }

    //断言型接口
    public void  test4(){
        List<String> list= Arrays.asList("he","aaaaa","ddddd","ddd","fffa");
        List<String> strings = filterStr(list, (s) -> s.length() > 3);

        for (String s: strings) {
            System.out.println(s);
        }

    }

    public List<String> filterStr(List<String> list, Predicate<String> pre){
       List<String> strList=new ArrayList<>();
        for (String str : strList) {
            if (pre.test(str)){
                strList.add(str);
            }

        }
        return strList;
    }
}

5、方法引用和构造器引用

方法引用:如果Lambda体中的内容已有方法实现,我们则可以使用方法引用
语法:

  • 对象实例::方法名
  • 类名::静态方法名
  • 类名::实例方法名

注意:
1、lambda中调用的方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型一致
2、 若lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数是,可以使用类名::方法名

package com.xuzhi.lambda;

/**
 * Author: 徐志
 * Date: 2020/8/1 14:24
 */

import com.xuzhi.entity.Employee;
import org.junit.Test;

import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 方法引用:如果Lambda体中的内容已有方法实现,我们则可以使用方法引用
   对象实例::方法名
   类::静态方法名
   类::实例方法名

   lambda中调用的方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型一致
   若lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数是,可以使用类名::方法名

 */
public class TestMethodRef {
    //对象实例::方法名
    @Test
    public void test1(){
        Consumer<String> con=(x)-> System.out.println(x);

       PrintStream ps= System.out;
       Consumer<String> con1=ps::println;
    }

    @Test
    public void test2(){
        Employee emp=new Employee();
        Supplier<String> sup=()->emp.getName();
        String s = sup.get();
        System.out.println(s);

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

    }

    //静态方法,类::静态方法名
    @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;
    }

    //构造器引用:需要调用的构造器和接口中一致
    public void test5(){
        Supplier<Employee> sup=()->new Employee();

        Supplier<Employee> sup2=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;

    }

}

6、lambda表达式小练习

package com.xuzhi.lambda;

import com.xuzhi.entity.Employee;
import com.xuzhi.function.NumFunction;
import com.xuzhi.function.StrFunction;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Author: 徐志
 * Date: 2020/8/1 11:48
 */
public class Zuoye {

    List<Employee> employees= Arrays.asList(
            new Employee("张三",18,9999.99),
            new Employee("李四",38,5555.99),
            new Employee("王五",50,6666.99),
            new Employee("赵六",16,3333.99),
            new Employee("田七",8,7777.99)
    );

    /**
     * 调用Collections.sort()方法,定制排序EMployee,先按照年龄比,年龄相同按照姓名比
     * 使用lambda表达式
     */
    @Test
    public void test1(){
        Collections.sort(employees,(e1,e2)->{
            if (e1.getAge()==e2.getAge()){
                return e1.getName().compareTo(e2.getName());
            }else{
                return Integer.compare(e1.getAge(),e2.getAge());
            }

        });

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

    //处理字符串,转大写
    @Test
    public void test2(){
        String s = srHandler("haha", (str) -> str.toUpperCase());
        System.out.println(s);

    }

    public String srHandler(String str, StrFunction sf){
        return sf.getValue(str);
    }

   //两个数操作
    @Test
    public void test3(){
        opreation(100L,200L,(x,y)->x+y);

        opreation(100L,200L,(x,y)->x*y);

    }

    public void opreation(Long l1, Long l2, NumFunction<Long,Long> mf){
        System.out.println(mf.getValue(l1,l2));
    }
}

总结

本人学习java8新特性观看的是B站的是尚硅谷的学习视频,所有代码均亲手所敲,在这里感谢尚硅谷。现在lambda表示式的使用也是非常的广泛,我们有必要掌握这些这些java新的特性,尤其是Spring框架中lambda表达式和Stream流的应用也是非常的广泛。工作中也会有应用。附上本人微信公众号二维码,希望大家关注,一起学习进步
在这里插入图片描述

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页