Lambda

Lambda 表达式的本质: 函数式接口的实例
函数式接口:@FunctionalInterface 标识的接口,只有一个抽象方法

核心函数式接口

接口名称 抽象方法
Consumer void accept(T t)
Supplier T get()
Predicate boolean test(T t)
Function<T,R> R apply(T)
Comparator int compare(T t1, T t2)

其它常用接口

Function 接口的子接口:
UnaryOperator # T apply(T t);
BiFunction<T,U,R> # R apply(T t , U u);
子接口:BinaryOperator # T apply(T t1 , T t2);
BiConsumer<T,U> # void accept(T t , U u);
BiPredicate<T,U> # boolean test(T t , U u );

方法引用

如果要传递给 Lambda 体的操作,已经有现成的实现方法了,可以使用方法引用;

要求:接口中抽象方法的参数列表和返回值类型,必须与方法引用的参数列表和返回值类型保持一致;

方法引用的格式

  1. 对象::实例方法名;
    例:employeeObj.getName() 与 Supplier 接口中的 T get() —> employeeObj::getName;
  2. 类::静态方法名;
    例:Comparator 接口中 int compare(T t1, T t2) 与 Integer中的静态方法:int compare(int x, int y) --> Integer::compare;
  3. 类::实例方法名;
    例:BiPredicate 中的 boolean test(T t , U u ) 与 String 类中的 boolean s1.equals(s2); --> String::equals;
    Comparator中的 int compare(int a,int b) 与 String 中的 s1.compareTo(s2) --> String::compareTo;
    Function 中的 R apply(T) 与 Employee 中的 String empObj.getName(); --> Employee::getName;

来一起看几个例子:

 @Testpublic void test03(){//Consumer 中的 void accept(T t)// PrintStream 中的 void println(T t)Consumer<String> con1 = str -> System.out.println(str);con1.accept("test");PrintStream ps = System.out;Consumer<String> con2 = ps::println;con2.accept("test");}@Testpublic void test04(){Employee emp = new Employee();emp.setName("hello");Supplier<String> sup1 = () -> emp.getName();System.out.println(sup1.get());Supplier<String> sup2 = emp::getName;System.out.println(sup2.get());}@Testpublic void test05(){Comparator<Integer> com1 = (i1,i2) -> Integer.compare(i1, i2);System.out.println(com1.compare(1, 2));System.out.println("=============>");// 类::静态方法Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(2, 1));}@Testpublic void test06(){/** 类 :: 实例方法* Comparator 中的 int compare(T t1, T t2)* String 中的 int t1.compareTo(t2)* */Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc", "abf")); // -3System.out.println("=============>");Comparator<String> com2 = String::compareTo;System.out.println(com2.compare("abc", "abd")); //-1//匿名子类的形式Comparator<String> com3 = new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}};}@Testpublic void test07(){//类::实体方法// BiPredicate 中的 boolean test(t1,t2)// String 中的 boolean t1.equals(t2)BiPredicate<String,String> p1 = (s1,s2) -> s1.equals(s2);System.out.println(p1.test("ab", "ab"));BiPredicate<String,String> p2 = String :: equals;System.out.println(p2.test("ab", "ab"));}@Testpublic void test08(){/*类::实体方法* Function中的 R apply(T t)* Employee 中的 String empObj.getName()* */Employee emp = new Employee("gcx", 18,180000.00);Function<Employee,String> func1 = e -> e.getName();System.out.println(func1.apply(emp));Function<Employee,String> func2 = Employee::getName;System.out.println(func2.apply(emp));}

Stream

Stream 对集合数据进行操作,可以执行复杂的查找过滤映射
特点:
Stream 本身无法存储元素;
不改变源对象;

创建 Stream 的四种方式

  1. Collection 接口中的默认方法 : stream()
    List 、Set、Queue等,直接调用 stream() 方法就可以获得 Stream;
    Stream stream2 = list.stream();
  2. Arrays 的静态方法: Arrays.stream(T[] array)
    Stream stream1 = Arrays.stream(new String[]{“d”,“e”,“f”});
  3. Stream 的静态方法 :Stream.of(T…values);
    Stream stream = Stream.of(“A”,“B”,“C”,“D”);
    ​ stream.forEach(System.out::println);
  4. 基于 Supplier;
    Stream s = Stream.generate(Supplier sp);
    s.limit(20).forEach(System.out::println);
    此种方式创建的 Stream 会不断调用 Supplier.get() 方法来产生下一个元素,打印的时候必须使用 limit() 使其先变成有限序列;

Stream 的优点:Stream几乎不占用空间,因为每个元素都是实时计算出来的,用的时候再算;

支持基本数据类型的流:
Java 的泛型不支持基本数据类型,我们无法使用 Stream 这样的类型,只能使用 Stream , 但是这样会频繁进行拆、装箱,影响效率;

java 标准库提供了 : IntStream LongStream 和 DoubleStream

// IntStream
IntStream stream = Arrays.stream(new int[]{1,2,3});
//LongStream
List<String> list1 = Arrays.asList("1","2","3");
LongStream longStream = list1.stream().mapToLong(Long::parseLong);
/**
LongStream mapToLong(ToLongFunction<? super T> mapper);
@FunctionalInterface
public interface ToLongFunction<T> {long applyAsLong(T value);
}
*/OptionalLong max = list1.stream().mapToLong(Long::parseLong).max();
Long asLong = max.getAsLong();

实例:打印斐波那契数列

@FunctionalInterface
public interface LongSupplier{long getAsLong();
}
class FibSupplier implements LongSupplier{public static long num =1 ;public long getAsLong(){return fib(num++);}public long fib(long num){if(num ==1 || num == 2){return 1;}else{return fib(num-2) + fib(num-1);}}
}
public class Test1{public static void main(String[] args){LongStream fib = LongStream.generate(new FibSupplier());//打印fib.limit(10).forEach(System.out::println);}
}

常见的Stream 操作

map()

Stream.map() 是 Stream 最常用的一个转换方法,把一个 Stream 转换为另一个 Stream;

所谓 map 操作,就是把一种运算操作映射到序列的每一个元素上

map(Function);

Arrays.asList("Apple","Pear","Orange","Banana").stream().map(String::trim).map(String::toLowerCase).forEach(System.out::println);

filter

filter(Predicate)

filter 可以对一个 Stream 的所有元素进行测试,不满足条件就扔掉,剩下的满足条件的元素就构成一个新的Stream;

reduce

reduce(T identity, BinaryOperator accumulator)
T apply(t1,t2) # 负责把上次累加的结果和本次的元素进行运算;
​ identity # 执行累加计算的初始值;

map 和 filter 都是 Stream 的转换方法,而 Stream.reduce() 是 Stream的一个聚合方法;把所有元素聚成一个结果;

// acc是上次计算的结果,初始为0;
int sum = Stream.of(1,2,3,4,5,6).reduce(0,(acc,n) -> acc + n );

如果去掉初始值,我们会得到一个 Optional:

Optional<Integer> opt = stream.reduce((acc,n) -> acc +n);
if(opt.isPresent()){​   System.out.println(opt.get());
}

因为 Stream 的元素有可能是 0 个,这样就没法调用 reduce() 的聚合函数了;

注意:
Stream 的转换操作 map 和 filter 并不会触发任何计算(只保存了转换规则);
聚合操作是真正需要从 Stream 请求数据的,会立刻促使 Stream 输出它的每一个元素;

输出为List

如果我们希望把 Stream 的元素保存到集合(把Stream变成list是一个聚合操作);

// 获得的实体类是 ArrayList
List<String> collect = stream.filter(s -> s!=null && !s.isEmpty()).collect(Collectors.toList());

输出为数组

A[] toArray(IntFunction<A[]> generator);
@FunctionalInterface

public interface IntFunction{
​ R apply(int value);
}

String[] strings = list.stream().toArray(String[]::new);

输出为 Map

Map<String,String> map = stream.collect(Collectors**.toMap(**
​   s -> s.substring(0,s.indexOf(":")),
​   s -> s.substring(s.indexOf(":") +1)
));

toMap 里面是两个 Function 实现类,分别对应 key的映射,和 value 的映射;

分组输出

List<String> list1 = Arrays.asList("Apple","Banana","Blackberry","Coconut", "Avocado","Cherry","Apricots");
//以单词的首字母分组;
Map<String,List<String>> collect1 = list1.stream().collect(Collectors.groupingBy(s -> s.substring(0,1),Collectors.toList()));

排序

// 要求每个元素必须实现 Comparable 接口;
stream.sorted().collect(Collectors.toList());
//传入比较规则;
stream.sorted(String::compareToIgnoreCase).collect(Collectors.toList());

去重

List<String> list2  = Arrays.asList("a","A","b","b","A");
List<String> collect2 = list2.stream().distinct().collect(Collectors.toList());

截取

//skip(2): 跳过前两个;
// limit(3) : 输出 3个;
List<String> collect2 = list2.stream().skip(2).limit(3).collect(Collectors.toList());

并行

将对 Stream 元素的单线程处理,变为并行处理:

stream.parallel().sorted().toArray(String[] :: new );

合并

Stream.comcat(s1,s2);

遍历

forEach(Consumer)
它可以循环处理 Stream 的每个元素,我们经常传入 System.out::println 来打印 Stream的元素;

flatMap

所谓 flatMap() 是把 Stream 的每个元素 (list) 映射为 Stream, 然后合并成一个新的 Stream

Stream<List<Integer>> s = Stream.of(
​   Arrays.asList(1,2,3),
​   Arrays.asList(4,5,6),
​   Arrays.asList(7,8,9)
);
Stream<Integer> i = s.flatMap(list -> list.stream());

最大、最小

max(Comparator<? super T> cp ) : 找出最大元素;

min(Comparator<? super T> cp ) : 找出最小元素;

测试 Stream 的元素是否满足条件

boolean allMatch(Predicate<? super T>) : 测试是否所有元素均满足测试条件
​boolean anyMatch(Predicate<? super T>) : 测试是否至少有一个元素满足测试条件

sum、average

针对IntStream 、 LongStream、 DoubleStream , 还额外提供了以下聚合方法:
​ sum() : 对所有元素求和;
​ average() : 对所有元素求平均数;

拼接流中的元素

//用 xxx 拼接流中的元素;
String s = list2.stream().collect(Collectors.joining("xxx"));

findFirst、orElse、orElseThrow

findFirst: 获取第一个元素,返回值是 Optional
orElse : 通常与 findFirst 配合使用,意思是,找不到就返回指定的默认值;
orElseThrow : 通常与 findFirst 配合使用,意思是,找不到就抛异常;

List<String> list2 = Arrays.asList("r","ba","c","sd","e","f");
String s1 = list2.stream().filter(s -> s.contains("a")).findFirst().orElse("haha");Optional<String> a1  = list2.stream().filter(s -> s.contains("a")).findFirst();String a1 = list2.stream().filter(s->s.contains("a")).findFirst().orElseThrow(RuntimeException::new);

Lambda Stream相关推荐

  1. lambda stream流处理异常的方法/Either不终止stream流处理异常

    lambda stream流处理异常的方法/Either不终止stream流处理异常 1.直接用try/catch捕获 1.1 stream流中使用try/catch 案例如下,在list中存在可能引 ...

  2. java stream foreach_Java 8 Lambda Stream forEach具有多个语句

    我仍在学习Lambda,请原谅我做错了什么 final Long tempId = 12345L; List updatedEntries = new LinkedList<>(); fo ...

  3. 零基础学习java------21---------动态代理,java8新特性(lambda, stream,DateApi)

    1. 动态代理 在一个方法前后加内容,最简单直观的方法就是直接在代码上加内容(如数据库中的事务),但这样写不够灵活,并且代码可维护性差,所以就需要引入动态代理 1.1 静态代理实现 在讲动态代理之前, ...

  4. parallel循环java_Java 8 lambda stream forEach parallel 等循环与Java 7 for each 循环耗时测试...

    Java 8 里面的stream 有串行流和并行流之分. 说高级的stream就是那个并行流.下面是那个并行流的简单实现.只要是继承Collection类的都可以这么用. list.stream(). ...

  5. java8 Lambda Stream collect Collectors 常用实例

    将一个对象的集合转化成另一个对象的集合 List<OrderDetail> orderDetailList = orderDetailService.listOrderDetails(); ...

  6. lambda stream 循环_jdk8-lambda-stream的使用

    1, 认识stream(声明式编程) Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator, 原始版本的Iterator,用户只能一个一 ...

  7. Java基础巩固(二)异常,多线程,线程池,IO流,Properties集合,IO工具类,字符流,对象流,Stream,Lambda表达式

    一.异常,多线程 学习目标 : 异常的概述 异常的分类 异常的处理方式 自定义异常 多线程入门 1 异常的概述 1.1 什么是异常? 异常就是程序出现了不正常情况 , 程序在执行过程中 , 数据导致程 ...

  8. JDK1.8中的Stream详解

    Stream简介 Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 XML ...

  9. stream of java_java8新特性之强大的Stream API

    Stream API Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作. 使用Stream API 对集合数据进行操作, ...

最新文章

  1. struts2+hibernate+Spring分层开发
  2. 【分块】#6278. 数列分块入门 2 (区间修改、查询权值c在区间中的排名)
  3. python十一:集合(set)
  4. (chap2 简单的Http协议) HTTP方法(2)其他方法
  5. 【机器学习】机器学习中缺失值处理方法大全(附代码)
  6. eclipse主题下载网站
  7. 【C++深度剖析教程6】C++之友元
  8. Mac计算器的计算过程怎么看?教你一键查看运算记录!
  9. grandMA2onPC控制UE4灯光
  10. 在HTML中什么表示水平线,HTML中加入水平线的标签是( )
  11. php 新浪微博登陆,PHP使用新浪微博登入第三方网站实例代码
  12. 瘦了红颜, 多了寂寞
  13. 几种常用的文件加密方法
  14. Linux 安装DockerMysql
  15. 第二个MFC实例:GPA计算器
  16. 不叹惜、不呼唤我也不哭泣
  17. 基于Montgomery算法的高速、可配置 RSA密码IP核硬件设计系列(五)——模幂模块(抵抗侧信道攻击)模块的设计实现方案
  18. 【计量经济学导论】02. 多元回归模型
  19. 中国联通再次下调国际漫游资费 最高降幅达90.42%
  20. 微信小程序通过css实现底部边大圆弧效果

热门文章

  1. 从头开始学习 Dojo,第 2 部分 使用 Dojo 掌握面向对象开发
  2. ps ax ps axu_ps4s梦想的力量
  3. ACM中涉及到的数学知识
  4. 使用python随机画几何图形(矩形、圆形、三角形...)
  5. 高炉顶压前馈控制(布料扰动)
  6. 企业微信小程序可用存储空间不足_企业微信小程序制作,小程序开发公司
  7. Python3.6.1 AES/ECB/padding PKCS5 方法的加密解密脚本实现
  8. Oracle 11g RAC安装--基于openfiler存储+多路径+udev方式
  9. 关于iOS 11 tableView自动布局懵逼的事
  10. 插画软件_插画家眼中的色彩互动