[Java] Lambda表达式

定义

  • 正常情况下,使用一个接口或抽象类,需要创建一个子类
  • 匿名类:实例化抽象类或接口后紧跟类定义(没有名字),从而使代码更加精简
  • 只有重写接口方法的一句话有用,其余的都可由编译器推断
  • Lambda方法:匿名方法,即把方法作为参数进行传递
  • Lambda表达式:应用在单一抽象方法接口(Single Abstract Method SAM)环境下的一种简化定义形式
  • 使用Lambda表达式必须具有接口,且接口中有且只有一个抽象方法
  • 使用Lambda表达式必须具有上下文推断,即方法的参数或局部变量类型必须为Lambda对应的接口类型,才可使用Lambda作为该接口的实例
  • Lambda表达式的内容不要超过三行
  • 有且只有一个抽象方法的接口,称为函数式接口
  • 实例化函数式接口主要是为了使用方法,即接口的实例化对象是只有函数的对象,故称函数对象
  • 演变过程(情景:找出满足要求的Hero)
    • 普通方法:定义判断方法,在for循环遍历中进行条件判断,筛选数据
    • 匿名类方法:定义接口,提供判断方法,通过匿名类实现,原判断方法接收判断对象和判断方法对象
    • Lambda表达式:简化匿名类的定义,只保留方法参数和方法体,中间加->
  • 基本语法
    • (参数) -> {方法体}
    • 只有一个参数,可以去掉()
    • 只有一行方法,可以去掉{} 

匿名类

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.Random;
 4    
 5 import charactor.Hero;
 6    
 7 public class TestLambda {
 8     public static void main(String[] args) {
 9         Random r = new Random();
10         List<Hero> heros = new ArrayList<Hero>();
11         for (int i = 0; i < 5; i++) {
12             heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
13         }
14         System.out.println("初始化后的集合:");
15         System.out.println(heros);
16         System.out.println("使用匿名类的方式,筛选出 hp>100 && damange<50的英雄");
17         HeroChecker checker = new HeroChecker() {
18             @Override
19             public boolean test(Hero h) {
20                 return (h.hp>100 && h.damage<50);
21             }
22         };
23            
24         filter(heros,checker);
25     }
26    
27     private static void filter(List<Hero> heros,HeroChecker checker) {
28         for (Hero hero : heros) {
29             if(checker.test(hero))
30                 System.out.print(hero);
31         }
32     }
33 }
View Code

接口

1 package lambda;
2  
3 import charactor.Hero;
4  
5 public interface HeroChecker {
6     public boolean test(Hero h);
7 }
View Code

Lambda表达式

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.Random;
 4  
 5 import charactor.Hero;
 6  
 7 public class TestLamdba {
 8     public static void main(String[] args) {
 9         Random r = new Random();
10         List<Hero> heros = new ArrayList<Hero>();
11         for (int i = 0; i < 5; i++) {
12             heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
13         }
14         System.out.println("初始化后的集合:");
15         System.out.println(heros);
16         System.out.println("使用Lamdba的方式,筛选出 hp>100 && damange<50的英雄");
17         filter(heros,h->h.hp>100 && h.damage<50);
18     }
19  
20     private static void filter(List<Hero> heros,HeroChecker checker) {
21         for (Hero hero : heros) {
22             if(checker.test(hero))
23                 System.out.print(hero);
24         }
25     }
26  
27 }
View Code

方法引用

  • 对象的引用传递可以实现不同的栈操作同一块堆内存空间
  • 技术早期阶段,希望针对于方法可以实现引用机制,在Spring框架中有相关功能
  • JDK 1.8后,方法也支持引用操作,相当于为方法定义了别名
  • 不再自己覆写接口,而是引用其他类中现成的方法实现接口,可节约代码量
  • 简化Lambda表达式在一些重复操作上的执行
  • 需要一个函数式接口,并设置好参数
  • 引用静态方法
    • 类名称 :: static 方法 ;
    • filter(heros, TestLambda::testHero);
  • 引用对象方法
    • 实例化对象 :: 普通方法 ;
    • filter(heros, testLambda::testHero);
  • 引用容器中的对象的方法
    • 特定类 :: 普通方法
    • filter(heros, Hero::matched);
  • 引用构造器
    • 类名称 :: new
    • 接口中的方法返回一个对象:public interface Supplier<T> {T get();}
    • 设计一个方法以这个接口为参数:public static List getList(Supplier<List> s){return s.get();}
    • 调用这个方法,有三种方式
      • 匿名类:Supplier<List> s = new Supplier<List>() {public List get() {return new ArrayList();}}; List list1 = getList(s);
      • Lambda表达式:List list2 = getList(()->new ArrayList());
      • 引用构造器:List list1 = getList(ArrayList::new);
 1 @FunctionalInterface
 2 interface IMessage<P,R>{
 3     public R zhuanhuan(P p);
 4 }
 5 
 6 public class MethodReference_Demo {
 7     public static void main(String[] args) {
 8         IMessage<Integer,String> msg = String::valueOf;
 9         String str = msg.zhuanhuan(1000);
10         //以上两句等价于
11         //String str = String.valueOf(1000);
12         System.out.println(str.replace("0", "9"));
13     }
14 }
View Code

 内建函数式接口

  • 任何语言推出了一项技术之后,都会在语言本身围绕这个技术点进行大量的结构性完善
  • 函数式接口可分为四类,定义函数式接口时,直接使用内置的四种类型即可
  • 功能型接口(Function<T,R>):接收一个参数,返回一个结果
  • 消费型接口(Consumer<T>):负责接收数据,且不返回结果
  • 供给型接口(Supplier<T>):不接受参数,但可返回结果
  • 断言型接口(Predicate<T>):进行判断操作

聚合操作

  • 快速的数据处理的操作,工作在类集上
  • Lambda表达式、方法引用、四个函数式接口
  • Collection的父接口Iterable接口中定义的方法
    • default void forEach(Consumer<? super T> action):对Iterable的每个元素执行给定的操作
    • Consumer<? super T> action:消费型函数接口,能接收参数,但没有返回值
    • foreach()只能只能实现输出,主要使用Iterator迭代
  • Stream可利用Collection接口提供的方法
    • 并行数据流计算:default Stream<E> parallelStream()
    • 数据流计算:default Stream<E> stream()
    • 性能高:流计算比Iterator迭代的性能快100倍左右
    • 语法简单
  • 聚合操作遍历数据
    • List<Hero> heros = new ArrayList<Hero>();
    • heros.stream().filter(h -> h.hp > 100 && h.damage < 50).forEach(h -> System.out.println(h.name));
  • Stream和管道
    • Stream是一系列元素,管道指聚合操作
  • 管道源
    • List<Hero> heros.stream()
  • 中间操作
    • 每个中间操作返回一个Stream,不会进行真正遍历
    • filter:匹配
    • distinct:去重
    • sorted:排序
    • sorted(Comparator<T>):指定排序
    • limit:取出的最大数据量
    • skip:跳过多少数据量
  • 结束操作
    • 不返回Stream,执行中间操作的行为
    • forEach():遍历每个元素
    • toArray():转换为数组
    • min(Comparator<T>):取最小元素
    • max(Comparator<T>):取最大元素
    • count():总数
    • findFirst():第一个元素

forEach()

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public class Stream_Demo {
 5     public static void main(String[] args) throws Exception{
 6         List<String> all = new ArrayList<String>();
 7         all.add("Hello");
 8         all.add("World");
 9         all.add("Good");
10         all.forEach(System.out::println);
11     }
12 }
View Code

判断包含“j”的单词个数

 1 import java.util.ArrayList;
 2 import java.util.Collections;
 3 import java.util.List;
 4 import java.util.stream.Stream;
 5 
 6 public class Stream_Demo {
 7     public static void main(String[] args) throws Exception{
 8         List<String> all = new ArrayList<String>();
 9         Collections.addAll(all,"Java","JavaScript","Ruby","Python");
10         Stream<String> stream = all.stream();
11         System.out.println(stream.filter((ele)->ele.toLowerCase().contains("j")).count());
12     }
13 }
View Code

取出包含“j”的单词

 1 import java.util.ArrayList;
 2 import java.util.Collections;
 3 import java.util.List;
 4 import java.util.stream.Collectors;
 5 import java.util.stream.Stream;
 6 
 7 public class Stream_Demo {
 8     public static void main(String[] args) throws Exception{
 9         List<String> all = new ArrayList<String>();
10         Collections.addAll(all,"Java","JavaScript","Ruby","Python");
11         Stream<String> stream = all.stream();
12         List<String> subList = stream.filter((ele)->ele.toLowerCase().contains("j")).collect(Collectors.toList());
13         System.out.println(subList);
14     }
15 }
View Code

取出1个包含“j”的单词,跳过1个元素

 1 import java.util.ArrayList;
 2 import java.util.Collections;
 3 import java.util.List;
 4 import java.util.stream.Collectors;
 5 import java.util.stream.Stream;
 6 
 7 public class Stream_Demo {
 8     public static void main(String[] args) throws Exception{
 9         List<String> all = new ArrayList<String>();
10         Collections.addAll(all,"Java","JavaScript","Ruby","Python");
11         Stream<String> stream = all.stream();
12         List<String> subList = stream.filter((ele)->ele.toLowerCase().contains("j")).skip(1).limit(1).collect(Collectors.toList());
13         System.out.println(subList);
14     }
15 }
View Code

 

MapReduce

  • Google提出的分布式数据处理模型
    • Map:对数据进行先期处理,可能需要计算、转型等
    • Reduce:数据的统计计算,针对处理好的数据内容进行统计操作

数据分析

 1 import java.util.ArrayList;
 2 import java.util.DoubleSummaryStatistics;
 3 import java.util.List;
 4 
 5 class Order{
 6     private String name;
 7     private double price;
 8     private int amount;
 9     public Order(String name, double price, int amount) {
10         this.name = name;
11         this.price = price;
12         this.amount = amount;
13     }
14     public String getName() {
15         return name;
16     }
17     public double getPrice() {
18         return price;
19     }
20     public int getAmount() {
21         return amount;
22     }    
23 }
24 
25 public class MapReduce_Demo {
26     public static void main(String[] args) throws Exception{
27         List<Order> all = new ArrayList<>();
28         all.add(new Order("PagePig",19.8,200));
29         all.add(new Order("BigPig",0.8,100));
30         all.add(new Order("WaWaPig",32000,10));
31         all.add(new Order("Java",100,200));
32         DoubleSummaryStatistics statistics = all.stream().filter((ele)->ele.getName().contains("Pig")).mapToDouble((orderObject)->orderObject.getPrice()*orderObject.getAmount()).summaryStatistics();
33         System.out.println("购买数量 "+statistics.getCount());
34         System.out.println("总花销 "+statistics.getSum());
35         System.out.println("最高价格 "+statistics.getMax());
36         System.out.println("最低价格 "+statistics.getMin());
37         System.out.println("平均价格 "+statistics.getAverage());
38     }
39 }
View Code
原文地址:https://www.cnblogs.com/cxc1357/p/12454444.html