java1.8 新特性 - Lambda表达式

排序接口优化

先来体验一下lambda最直观的优点:简洁代码

  //匿名内部类

  Comparator<Integer> cpt = new Comparator<Integer>() {

      @Override

      public int compare(Integer o1, Integer o2) {

          return Integer.compare(o1,o2);

      }

  };

  TreeSet<Integer> set = new TreeSet<>(cpt);

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

  //使用lambda表达式

  Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);

  TreeSet<Integer> set2 = new TreeSet<>(cpt2);

只需要一行代码,极大减少代码量!!

业务代码优化

 

这样一个场景,在商城浏览商品信息时,经常会有条件的进行筛选浏览,例如要选颜色为红色的、价格小于8000千的….

 

// 筛选颜色为红色

public  List<Product> filterProductByColor(List<Product> list){

    List<Product> prods = new ArrayList<>();

    for (Product product : list){

        if ("红色".equals(product.getColor())){

            prods.add(product);

        }

    }

    return prods;

 }

// 筛选价格小于8千的

public  List<Product> filterProductByPrice(List<Product> list){

    List<Product> prods = new ArrayList<>();

    for (Product product : list){

        if (product.getPrice() < 8000){

            prods.add(product);

        }

    }

    return prods;

 }

我们发现实际上这些过滤方法的核心就只有if语句中的条件判断,其他均为模版代码,每次变更一下需求,都需要新增一个方法,然后复制黏贴,假设这个过滤方法有几百行,那么这样的做法难免笨拙了一点。如何进行优化呢?

优化一:使用设计模式

定义一个MyPredicate接口

public interface MyPredicate <T> {

    boolean test(T t);

}

如果想要筛选颜色为红色的商品,定义一个颜色过滤类

public class ColorPredicate implements MyPredicate <Product> {

 

     private static final String RED = "红色";

 

     @Override

     public boolean test(Product product) {

         return RED.equals(product.getColor());

     }

 

定义过滤方法,将过滤接口当做参数传入,这样这个过滤方法就不用修改,在实际调用的时候将具体的实现类传入即可。

 

 

 

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){

        List<Product> prods = new ArrayList<>();

        for (Product prod : list){

            if (mp.test(prod)){

                prods.add(prod);

            }

        }

        return prods;

    }

例如,如果想要筛选价格小于8000的商品,那么新建一个价格过滤类既可

 

public class PricePredicate implements MyPredicate<Product> {

    @Override

    public boolean test(Product product) {

        return product.getPrice() < 8000;

    }

}

这样实现的话可能有人会说,每次变更需求都需要新建一个实现类,感觉还是有点繁琐呀,那么再来优化一下

优化:使用lambda表达式

定义过滤方法:

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){

        List<Product> prods = new ArrayList<>();

        for (Product prod : list){

            if (mp.test(prod)){

                prods.add(prod);

            }

        }

        return prods;

    }

测试方法:

public void test(){

MyPredicate<Product> mp = new PricePredicate();

      List<Product> products = filterProductByPredicate(proList, mp);

         //打印过滤结果

      for (Product pro : products){

          System.out.println(pro);

      }

  }

 

 

使用lambda表达式进行过滤,这里就不需要实现MyPredicate 接口的PricePredicate类了

 

@Test

public void test(){

      List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);

         //打印过滤结果

      for (Product pro : products){

          System.out.println(pro);

      }

  }

 

 

 

 

在jdk1.8中还有更加简便的操作 Stream API

 

优化四:使用Stream API

 

甚至不用定义过滤方法,直接在集合上进行操作

 

// 使用jdk1.8中的Stream API进行集合的操作

@Test

public void test(){

    // 根据价格过滤

    proList.stream()

           .fliter((p) -> p.getPrice() <8000)

           .limit(2)

           .forEach(System.out::println);

 

    // 根据颜色过滤

    proList.stream()

           .fliter((p) -> "红色".equals(p.getColor()))

           .forEach(System.out::println);

 

    // 遍历输出商品名称

    proList.stream()

           .map(Product::getName)

           .forEach(System.out::println);

}

 

 

 

 

Lmabda表达式的语法总结: () -> ();

 

前置       语法

无参数无返回值    () -> System.out.println(“Hello WOrld”)

有一个参数无返回值    (x) -> System.out.println(x)

有且只有一个参数无返回值       x -> System.out.println(x)

有多个参数,有返回值,有多条lambda体语句    (x,y) -> {System.out.println(“xxx”);return xxxx;};

有多个参数,有返回值,只有一条lambda体语句 (x,y) -> xxxx

口诀:左右遇一省括号,左侧推断类型省

 

注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念

什么是函数式接口? 
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface

常见的四大函数式接口

1消费型接口

Consumer 《T》:消费型接口,有参无返回值

@Test

    public void test(){

        changeStr("hello",(str) -> System.out.println(str));

    }

 

    /**

     *  Consumer<T> 消费型接口

     * @param str

     * @param con

     */

    public void changeStr(String str, Consumer<String> con){

        con.accept(str);

    }

 

 

2供给型接口

  • Supplier 《T》:供给型接口,无参有返回值

@Test

    public void test2(){

        String value = getValue(() -> "hello");

        System.out.println(value);

    }

    /**

     *  Supplier<T> 供给型接口

     * @param sup

     * @return

     */

    public String getValue(Supplier<String> sup){

        return sup.get();

}

 

3函数式接口

  • Function 《T,R》::函数式接口,有参有返回值

@Test

    public void test3(){

        Long result = changeNum(100L, (x) -> x + 200L);

        System.out.println(result);

    }

 

    /**

     *  Function<T,R> 函数式接口

     * @param num

     * @param fun

     * @return

     */

    public Long changeNum(Long num, Function<Long, Long> fun){

        return fun.apply(num);

    }

 

 

 

4断言型接口

  • Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型

public void test4(){

        boolean result = changeBoolean("hello", (str) -> str.length() > 5);

        System.out.println(result);

    }

 

    /**

     *  Predicate<T> 断言型接口

     * @param str

     * @param pre

     * @return

     */

    public boolean changeBoolean(String str, Predicate<String> pre){

        return pre.test(str);

    }

在四大核心函数式接口基础上,还提供了诸如BiFunction、BinaryOperation、toIntFunction等扩展的函数式接口,都是在这四种函数式接口上扩展而来的,不做赘述。

总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了,贴

方法引用

若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”

也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单

 

 

猜你喜欢

转载自blog.csdn.net/zzqcsdn123/article/details/85199083