目录

1.引入lambda表达式

2.lambda表达式六种语法格式:

3.java8内置的四大核心函数式接口

4.方法引用、构造器引用、数组引用


Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口
演示代码下载地址:https://github.com/prettyRain/java8demo.git

1.引入lambda表达式

1)用接口Runnable演示

@Test
    public void test6(){
        //以前的匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("lambda");
            }
        };
        runnable.run();
        
        //现在的lambda表达式
        Runnable runnable1 = () -> System.out.println("lambda");
        runnable1.run();
    }

2)自己写接口演示普通调用、匿名内部类调用、lambda表达式调用
Student类 用于演示的学生对象

package com.ge.lambda;

import java.math.BigDecimal;

/**
 * 学生类
 */
public class Student {

    public static String getStr(Integer grade){

        if(Integer.compare(grade,60) > 0){
            return "三好学生";
        }
        return "不及格";
    }
    private Long id;//id
    private String name;//学生姓名
    private String sex;//性别
    private Integer age;//年龄
    private BigDecimal price;//工资
    public Student() {
    }
    public Student(Long id, String name, String sex, Integer age, BigDecimal price) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.price = price;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (!id.equals(student.id)) return false;
        if (!name.equals(student.name)) return false;
        if (!sex.equals(student.sex)) return false;
        if (!age.equals(student.age)) return false;
        return price.equals(student.price);
    }
    @Override
    public int hashCode() {
        int result = id.hashCode();
        result = 31 * result + name.hashCode();
        result = 31 * result + sex.hashCode();
        result = 31 * result + age.hashCode();
        result = 31 * result + price.hashCode();
        return result;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", price=" + price +
                '}';
    }
}

接口 FilterStudent

package com.ge.lambda;
/**
 * 接口
 */
public interface FilterStudent<T> {
    public boolean test(T t);
}

FilterStudentForAgeImpl 判断年龄接口实现类

package com.ge.lambda;
import java.math.BigDecimal;
/**
 * 判断学生工资的实现类
 */
public class FilterStudentForPriceImpl implements FilterStudent<Student> {
    @Override
    public boolean test(Student student) {
        if(student.getPrice().compareTo(new BigDecimal(5000)) >= 0){
            return true;
        }
        return false;
    }
}

普通调用、匿名内部类调用、lambda表达式调用

Student[]  aa = new Student[]{new Student(1L,"小明","男",18,new BigDecimal(5000)),
                                  new Student(2L,"小花","女",12,new BigDecimal(6000)),
                                  new Student(3L,"小李","男",10,new BigDecimal(3000)),
                                  new Student(4L,"小刘","男",17,new BigDecimal(9000)),
                                  new Student(5L,"小刚","男",13,new BigDecimal(8000))};
//策略设计模式
    public List<Student> filterStudent(List<Student> students,FilterStudent<Student> filterStudent){
        List<Student> studentList = new ArrayList<Student>();
        for(Student student:students){
            if(filterStudent.test(student)){
                studentList.add(student);
            }
        }
        return studentList;
    }
    /**
     * 普通调用实现类
     */
    @Test
    public void test3(){
       List<Student> listForAge = filterStudent(stus,new FilterStudentForAgeImpl());
       for(Student student:listForAge){
           System.out.println(student.toString());
       }
       System.out.println("-----------------------------");
       List<Student> listForPrice = filterStudent(stus,new FilterStudentForPriceImpl());
        for(Student student:listForPrice){
            System.out.println(student.toString());
        }
    }
    /**
     * 通过匿名类实现
     */
    @Test
    public void test4(){
        List<Student> list = filterStudent(stus,new FilterStudent<Student>(){
            @Override
            public boolean test(Student student) {
                if(student.getAge() > 13){
                    return true;
                }
                return false;
            }
        });
        for(Student student:list){
            System.out.println(student.toString());
        }
    }
    /**
     * lambda表达式调用
     */
    @Test
    public void test5(){
        List<Student> list = filterStudent(stus,(e) -> e.getAge() >=  12 );
        for(Student student:list){
            System.out.println(student.toString());
        }

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

        List<Student> list1 = filterStudent(stus,(e) -> e.getPrice().compareTo(new BigDecimal(8000)) >= 0 );
        for(Student student:list1){
            System.out.println(student.toString());
        }
    }

2.lambda表达式六种语法格式:

  • 1)lambda表达式的基本语法
    • 箭头操作符将lambda表达式拆分成两部分;
      左侧:lambda表达式的参数列表
      右侧:lambda表达式中所需要执行的功能,即lambda体
  • 2)语法格式:
    • 语法格式一:无参数,无返回值
      () -> System.out.println("Hello Lambda!");
    • 语法格式二:有一个参数,并且无返回值
      (x) -> System.out.println(x)
    • 语法格式三:若只有一个参数,小括号可以省略不写
      x -> System.out.println(x)
    • 语法格式四:有两个以上参数,有返回值,并且lambda体中有多条语句
      Comparator<Integer> com = (x, y) -> {
      System.out.println("函数式接口");
      return Integer.compare(x, y);
      };
    • 语法格式五:若 Lambda 体中只有一条语句,有返回值, return 和 大括号都可以省略不写
      Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    • 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
      (Integer x, Integer y) -> Integer.compare(x, y);
package com.ge.lambda;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/*
 * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
 * 箭头操作符将 Lambda 表达式拆分成两部分:
 *     左侧:Lambda 表达式的参数列表
 *     右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 * 语法格式一:无参数,无返回值
 *      () -> System.out.println("Hello Lambda!");
 * 语法格式二:有一个参数,并且无返回值
 *      (x) -> System.out.println(x)
 * 语法格式三:若只有一个参数,小括号可以省略不写
 *      x -> System.out.println(x)
 * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
 *      Comparator<Integer> com = (x, y) -> {
 *          System.out.println("函数式接口");
 *          return Integer.compare(x, y);
 *      };
 *
 * 语法格式五:若 Lambda 体中只有一条语句,有返回值, return 和 大括号都可以省略不写
 *      Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
 *
 * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
 *      (Integer x, Integer y) -> Integer.compare(x, y);
 *
 *
 * 二、Lambda 表达式需要“函数式接口”的支持
 * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
 *           可以检查是否是函数式接口
 */
public class TestLambda2 {
    /**
     * 无参 无返回值
     */
    @Test
    public void test1(){
        Runnable r = () -> System.out.println("lambda");
        r.run();
    }
    /**
     * 有一个参数,并且无返回值
     */
    @Test
    public void test2(){
        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("有一个参数,并且无返回值");
    }
    /**
     * 若只有一个参数,小括号可以省略不写
     */
    @Test
    public void test3(){
        Consumer<String> con = x -> System.out.println(x);
        con.accept("若只有一个参数,小括号可以省略不写");
    }
    /**
     * 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
     */
    @Test
    public void test4(){
        Comparator<Integer> comparator = (x,y) -> {
            System.out.println("函数式接口");
            return Integer.compare(x,y);
        };
        System.out.println(comparator.compare(5,6));
    }
    /**
     * 若 Lambda 体中只有一条语句,有返回值, return 和 大括号都可以省略不写
     */
    @Test
    public void test5(){
        Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
        System.out.println(comparator.compare(5,6));
    }
    /**
     * Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
     */
    @Test
    public void test6(){
        Comparator<Integer> comparator = (Integer x,Integer y) -> Integer.compare(x,y);
        System.out.println(comparator.compare(5,6));
    }
}

3.java8内置的四大核心函数式接口

  • 1)Consumer<T> : 消费型接口
    方法: void accept(T t)
  • 2)Supplier<T> : 供给型接口
    方法: T get();
  • 3)Function<T, R> : 函数型接口
    方法: R apply(T t);
  • 4)Predicate<T> : 断言型接口
    方法: boolean test(T t);

package com.ge.lambda;

import org.junit.Test;

import javax.print.DocFlavor;
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;

/*
 * Java8 内置的四大核心函数式接口
 *
 * 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(){
        Consumer<String> consumer = x -> System.out.println(x);
        consumer.accept("consumer消费型接口");
    }
    /**
     * Supplier<T>供给型接口
     */
    @Test
    public void test2(){
        Supplier<Integer> supplier= () -> (int)(Math.random()*100);
        System.out.println(supplier.get());
    }
    /**
     * Function(T,R)函数型接口
     */
    @Test
    public void test3(){
        String resultstr = strHander("jjfsdjsjdsjiojwijf",(x) -> x.substring(2,5));
        System.out.println(resultstr);
    }
    public String strHander(String str, Function<String,String> fun){
        return  fun.apply(str);
    }

    /**
     * 断言型接口
     */
    @Test
    public void test4(){
        List<String> list = Arrays.asList("aaa","bbb","cccc","dddd");
        List<String> returnlist = getList(list,(x) -> x.length() > 3);
        System.out.println(Arrays.toString(returnlist.toArray()));
    }
    public List getList(List<String> list, Predicate<String> predicate){
        ArrayList<String> returnlist = new ArrayList();
        for(String str:list){
            if(predicate.test(str)){
                returnlist.add(str);
            }
        }
        return returnlist;
    }
}

4.方法引用、构造器引用、数组引用

  • 1)方法引用:若lambda体中的功能,已经有方法提供了实现,可以使用方法引用(可以理解为lambda表达式的另一种表现形式)
    • 1.对象的引用::实例方法名
    • 2.类名::静态方法名
    • 3.类名::实例方法名
    • 注意:①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
      ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
  • 2)构造器引用:构造器的参数列表,需要与函数式接口中参数列表保持一致
  • 1.类名::new
  • 3)数组引用
  • 1.类型[]::new
    /**
     * 对象的引用 :: 实例方法名
     */
    @Test
    public void test1(){
        //消费型
        Consumer<String> consumer = (x) -> System.out.println(x);
        Consumer<String> consumer1 = System.out::println;
        consumer.accept("consumer:以前的写法");
        consumer.accept("consumer1:现在的写法");
        //供给型
        Student student = new Student(1l,"小明","男",12,new BigDecimal(2000));
        Supplier<String> supplier = student::getName;
        System.out.println(supplier.get());
    }
    /**
     * 类名 :: 静态方法名
     */
    @Test
    public void test2(){
        //函数型接口
        Function<Integer,String> fun = Student::getStr;
        System.out.println(fun.apply(100));
    }
    /**
     * 类名 :: 实例方法名   把类名当一个参数来处理
     */
    @Test
    public void test3(){
        //断言型接口
        BiPredicate<String,String>  biPredicate = (x,y) -> x.equals(y);
        System.out.println(biPredicate.test("222","333"));

        BiPredicate<String,String> biPredicate1 = String::equals;
        System.out.println(biPredicate1.test("222","333"));

        Function<Student,String> fun = (e) -> e.toString();
        System.out.println(fun.apply(new Student(1l,"小明","男",12,new BigDecimal(2000))));

        Function<Student,String> fun1 = Student::toString;
        System.out.println(fun.apply(new Student(1l,"小明","男",12,new BigDecimal(2000))));
    }
    /**
     * 构造器引用
     */
    @Test
    public void test4(){
       Supplier<Student> supplier = () -> new Student(1l,"小明","男",12,new BigDecimal(2000));
       System.out.println(supplier.get().toString());

       Supplier<Student> studentSupplier = Student::new;
       System.out.println(studentSupplier.get().toString());
    }
    /**
     * 数组引用
     */
    @Test
    public void test5(){
       //函数型接口
        Function<Integer,String[]> function = (x) -> new String[x];
        System.out.println(function.apply(3).length);

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

5 合并数组和去重

{
        return data
                .stream()
                .collect(Collectors.groupingBy(WorkOrderModel::getWorkOrderType))
                .entrySet()
                .stream()
                .map(item -> {
                    Integer workOrderTyepe = item.getKey();
                    List<GroupsItem> groupsItemList = item
                            .getValue()
                            .stream()
                            .map(ele -> ele.getGroups().stream()
                                    .map(el -> {
                                        GroupsItem groupsItem = new GroupsItem();
                                        BeanUtils.copyProperties(el, groupsItem);
                                        groupsItem.setWosId(ele.getId());
                                        return groupsItem;
                                    })
                                    .collect(Collectors.toList()))
                            .collect(Collectors.toList())
                            .stream()
                           .collect(ArrayList<RuleObj>::new, ArrayList::addAll, ArrayList::addAll);
                    if (CollectionUtils.isEmpty(groupsItemList)) {
                        return null;
                    }
                    groupsItemList.sort((o1, o2) -> o2.getUpdatedAt().compareTo(o1.getUpdatedAt()));
                    Map<String, GroupsItem> groupsItemMap = new HashMap<>();
                    for (GroupsItem group : groupsItemList) {
                        String key = group.getKey();
                        GroupsItem groupsItem = groupsItemMap.get(key);
                        if (groupsItem != null) {
                            continue;
                        }
                        groupsItemMap.put(key, group);
                    }
                    return new OrderGroups(workOrderTyepe, rebuildGroupMaps(groupsItemMap));
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(OrderGroups::getTemplateId, OrderGroups::getGroupsItemMap));
    }

如上代码所示可以通过(对内部的两个数组进行合并)

 .collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);

去重

List<ImageInfo> imageList = remoteDcoreService.getDriverImages(driverInfo.getDriverId());
imageList = imageList
        .stream()
        .collect(Collectors.collectingAndThen(Collectors.toCollection(()
        -> new TreeSet<>(Comparator.comparing(ImageInfo::getType))), ArrayList::new));

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐