定义
- 正常情况下,使用一个接口或抽象类,需要创建一个子类
- 匿名类:实例化抽象类或接口后紧跟类定义(没有名字),从而使代码更加精简
- 只有重写接口方法的一句话有用,其余的都可由编译器推断
- 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 }
接口
1 package lambda; 2 3 import charactor.Hero; 4 5 public interface HeroChecker { 6 public boolean test(Hero h); 7 }
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 }
方法引用
- 对象的引用传递可以实现不同的栈操作同一块堆内存空间
- 技术早期阶段,希望针对于方法可以实现引用机制,在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 }
内建函数式接口
- 任何语言推出了一项技术之后,都会在语言本身围绕这个技术点进行大量的结构性完善
- 函数式接口可分为四类,定义函数式接口时,直接使用内置的四种类型即可
- 功能型接口(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 }
判断包含“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 }
取出包含“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 }
取出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 }
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 }