jdk8新特性lambda表达式和Stream Api的使用总结

一.lambda 表达式

lambda 表达式 是 java jdk 1.8的新特性,面向函数编程,它简化了编码.让代码变得简单优雅.(但个人觉得 这个有点骚气) 高大上的感觉.

1.它的使用规则
lambda表达式:

   (parameters) -> expression
或
(parameters) ->{ statements; }
  可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式

简单的实例:
// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

通用的规律是:
小括号指向大括号,小括号里面放参数,大括号里面写代码。

举个例子:

(Integer n1,Integer n2) -> n1 + n2
这个就相当于

Integer method(Integer n1, Integer n2) {
return n1 + n2;
}

常用场景:
列表迭代:
List list= Arrays.asList(1, 2, 3, 4, 5);
list.forEach(x -> System.out.println(x));

线程:
new Thread (() -> System.out.println(“线程开启!”)).start()

二.Stream Api

1.概述

Java 8 引入的一个重要的特性无疑是 Stream API。Stream 翻译过来是“流”,突然想到的是大数据处理有个流式计算的概念,数据通过管道经过一个个处理器(Handler)进行筛选,聚合,而且流都具有向量性,强调的是对数据的计算处理,而集合强调的是数据集。Stream可以看做是一个可操作的数据集序列,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。有点类似于数据库中的增删改查操作。十分高效而且易于使用。

它的特点

①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

中间可使用的操作

筛选与切片:

filter——接收 Lambda , 从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

查找与匹配:

allMatch–检查是否匹配所有元素
anyMatch–检查是否至少匹配一个元素
noneMatch–检查是否没有匹配所有元素
findFirst–返回第一个元素
findAny–返回当前流中的任意元素

count–返回流中元素的总个数
max–返回流中最大值
min–返回流中最小值

归约:

reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
——可以将流中元素反复结合起来,得到一个值。

最终汇聚 collect

collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

1、collect在流中生成列表,map,等常用的数据结构
2、toList()

3、toSet()

4、toMap()

collect是基于Collectors实现的,而Collectors除了上面的to…之外还有
maxBy:最大
minBy:最小
summingDouble:求和
averagingDouble:平均值
counting:计数
summarizingDouble:统计,上面5种都包括
groupingBy:分组(可以自定义分组,可以多级分组)
partitioningBy:分区,将满足条件的分成一个区,不满足的分成一个区
joining:连接字符串,delimiter:分割符,prefix:前缀,suffix:后缀
reducing:归约

Sreeam Api 的使用 需要结合lambda 表达式 ,所以 学习stream api 之前 需要对了lambda 表达式有一定的了解.

groupingBy 分组
 public static void main(String[] args) {
        // 根据市场类型 查询 出所有的股票代码 数据 
        List<EtfStockNote> stocks = getDimAllConstituentStocks(DimEtfIopvQuery.getDimEtfFoundCodeByMarkType("102"));
        // 这里面 一个基金有多个成分股,所以 想构造出 key 是 基金, 使用一个集合装成分股信息
        Map<String, List<EtfStockNote>> listMap = stocks.stream().collect(Collectors.groupingBy(EtfStockNote::getFundCode));
        for (Map.Entry<String, List<EtfStockNote>> entry : listMap.entrySet()) {
            System.out.println(entry);
        }
    }
2.用法

举个例子:

public static void test() {
        // 需求是 我要从这list中找出 是会员的地址 且用户积分最高前三位 然后 只需要用户电话和地址.
        ArrayList<User> list = new ArrayList<>();
        list.add(new User(2000, "北京朝阳", "18601980988", true));
        list.add(new User(599, "北京海淀", "135019809122", false));
        list.add(new User(660, "杭州西湖", "18501980988", true));
        list.add(new User(1200, "杭州滨江", "13701980933", true));
        list.add(new User(150, "北京昌平", "152019809789", true));
        list.add(new User(980, "杭州上城", "152019809782", true));
        list.add(new User(980, "北京大兴", "152019809679", true));
        // 这个就是从集合list形成流 然后过滤是会员的 排序根据用户积分 然后去前三位 之后只取出 用户的电话和地址
        Map<String, String> collect = list.stream().filter(k -> k.getMembers()).
                sorted((t1, t2) -> t2.getIntegral() - t1.getIntegral()).limit(3).
                collect(Collectors.toMap(User::getPhoneNum, User::getAddr, (k1, k2) -> k2));

  //这里解释一下  (k1, k2) -> k2) 这个的意思如果key 相同时 是去前一个还是后一个,这里取得是后一个key

// 为了能一步步分析 我这边先做个拆解

        // 把 list 转换为 stream 流
        Stream<User> stream = list.stream();
        // 这里的过滤写法和形式有好几种  可根据需要来

        //1.要过滤是会员 的

        // k.getMembers() 这个 K 就是个参数 随便定义 他代表的就是 User 对象
        // k.getMembers() 的意思获取会员 得到一个布尔值 true/flase
        stream.filter(k->k.getMembers())

        // 2. 要 获取用户地址 是北京的

        stream.filter(k->{
            if(k.getAddr().contains("北京")){

            }
        }).collect() // if 写要处理的逻辑 然后再转成需要的集合

        // 下边的分析就简单了
        //获取会员然后排序  limit 是取值
        stream.filter(k->k.getMembers()).sorted((t1, t2) -> t2.getIntegral() - t1.getIntegral())
                // 这里 是遍历对象 获取什么值做key 什么做 value
        //讲下这个 :: 这两个是对含有user 集合遍历取值

        collect(Collectors.toMap(User::getPhoneNum, User::getAddr, (k1, k2) -> k2));

}
public class UserEntity implements Serializable {
	private Integer id;
    private String userName;
    private String phone;
}

public static void main(string args[]){
	List<UserEntity> users=new ArrayList<>();
 
    users.add(new UserEntity(1,"张三","18399990000"));
    users.add(new UserEntity(2,"王五","18399990023"));
    users.add(new UserEntity(3,"里斯","18399990005"));
    // 获取list中所有对象的某个属性
    List<String> courseIds=  users.stream().map(UserEntity::getUserName).collect(Collectors.toList());
}

通过以上可以了解到 它的大致用法 ,其实 list set map 都是同理.

并发

1、stream替换成parallelStream或 parallel

2、输入流的大小并不是决定并行化是否会带来速度提升的唯一因素,性能还会受到编写代码的方式和核的数量的影响

3、影响性能的五要素是:数据大小、源数据结构、值是否装箱、可用的CPU核数量,以及处理每个元素所花的时间

Optional 的用法

1、Optional 是为核心类库新设计的一个数据类型,用来替换 null 值。

2、人们对原有的 null 值有很多抱怨,甚至连发明这一概念的Tony Hoare也是如此,他曾说这是自己的一个“价值连城的错误”

3、用处很广,不光在lambda中,哪都能用

4、Optional.of(T),T为非空,否则初始化报错

5、Optional.ofNullable(T),T为任意,可以为空

6、isPresent(),相当于 !=null

7、ifPresent(T), T可以是一段lambda表达式 ,或者其他代码,非空则执行

 //对 optional 的用法使用
    public static void test() {
        User u = null;
        User user = new User(007, "北京", "18601998088", true);
        // 你可以使用  of() 和 ofNullable() 方法创建包含值的 Optional。
        // 两个方法的不同之处在于如果你把 null 值作为参数传递进去,of() 方法会抛出 NullPointerException:
//        Optional<User> u1 = Optional.of(u);
//        System.out.println(u1); // 会报错 空指针异常
        Optional<User> u2 = Optional.ofNullable(u);
        System.out.println(u2); // 这个 传入为null 不会报错 会输出  Optional.empty
        //所以不确定传入的值是否为null  则 选择ofNullable 来创建Optional 实例

        //返回默认值 orElse 的用法
        User uu = null;
        User uuser = new User(007, "北京", "18601998088", true);

        // 这里 uu 对象是空的,所以返回了作为默认值的 uuser。
        User result = Optional.ofNullable(user).orElse(uuser);
        System.out.println(result); // 这里会输出 默认值 也就是 uuser 的值

        // 如果对象的初始值不是 null,那么默认值会被忽略:
        User user2 = new User(007, "北京", "18601998088", false);
        User user3 = new User(007, "北京", "18601998088", true);
        User orElse = Optional.ofNullable(user2).orElse(user3);
        System.out.println(orElse);// 这里因为 user2 不为null 所以默认值不会输出

        //orElse() 和 orElseGet() 的不同之处

        User user = new User("john@gmail.com", "1234");
        logger.info("Using orElse");
        User result = Optional.ofNullable(user).orElse(createNewUser());
        logger.info("Using orElseGet");
        User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());

        /**
         * 结论:  当对象为空而返回默认对象时,行为并无差异
         *       当两个 Optional  对象都包含非空值,两个方法都会返回对应的非空值。
         *       不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象
         */


        // 转换值

        //map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。
        // 这就使对返回值进行链试调用的操作成为可能 —— 
        //这里的下一环就是 orElse()。
        User user4 = new User(007, "北京", "18601998088", true);
        String s = Optional.ofNullable(user4).map(o -> o.getAddr()).orElse("地址不详");

        //过滤 filter
        Optional<User> userOptional = Optional.ofNullable(user4).filter(u -> u.getAddr().
        contains("北京"));
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值