栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

奇怪的JAVA笔记 | JAVA8简单又详细的快速入门笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

奇怪的JAVA笔记 | JAVA8简单又详细的快速入门笔记

目录

背景

一个简单的lambda表达式例子 

函数式接口

谓词逻辑

基础操作总结

遍历

map

flatMap与map

查找与匹配 

元素连接joining

规约reduce

Optional

流操作过程的理解

收集器Collectors

分组收集groupingBy

聚合操作/统计

有状态操作与无状态操作

limit(n)

skip(n)

distinct()

去重拓展

sorted()

排序拓展

并行流


背景

个人复习总结笔记,可能有点乱吼,后续学习继续完善,白话+自己的理解

一个简单的lambda表达式例子 
public interface Demo {
    void test(String a);
}

一个功能接口作为参数进行传递的简化(原始->lambda)

public class TestMethod {
    public static void main(String[] args) {
        //原始:一个功能接口的实现
        Demo demo = new Demo() {
            @Override
            public void test(String a) {
                System.out.println(a);
            }
        };
        //简化
        Demo demo1 = (String a) ->{
            System.out.println(a);
        };
        //进一步简化
        Demo demo2 = a -> System.out.println(a);
        //TestMethod testMethod = new TestMethod();
        //testMethod.print("test",a -> System.out.println(a));

        TestMethod testMethod = new TestMethod();
        testMethod.print("test",demo);
    }

    //通过传入不同的Demo接口的实现完成不同的功能
    public void print(String a,Demo demo){
        demo.test(a);
    }
}

集合List,数组,文件流能用Stream

集合list.stream

数组Stream.of(array)

文件流

此处接口中如果存在多个方法,则不能使用lambda表达式,因为不知道会调用哪个方法,故考虑

函数式接口

特点:只有一个抽象方法(没有方法的实现),可定义静态非抽象,可定义默认非抽象(带有函数体)方法default(实现类可以不用实现),可以不带@FunctionalInterface,允许存在java.lang.Object中的public方法,如equals

谓词逻辑

谓语,用来修饰限定主语

如Predicate 用于校验的谓词逻辑,当一个判断逻辑多出地方用到,就可以提取出来

简单理解为一个lambda表达式抽取出来

多个谓词逻辑共同成立 用.and()连接 表示共同成立,其他连接词根据业务逻辑来定

如 .or()或 .negate() 取相反的类似非

        List users = Arrays.asList(new User(12,"M"),new User(null,"M"));
//        List user2 = users.stream().filter(e -> {
//            if(e.getAge() == null){
//                e.setAge(100);
//                return true;
//            }
//            return e.getAge() != null && e.getAge() > 10;
//        }).collect(Collectors.toList());
        List user2 = users.stream().filter(predicateTest()).collect(Collectors.toList());
        user2.stream().forEach(System.out::print);
    }


    static Predicate predicateTest() {
        return e -> {
            if(e.getAge() == null){
                e.setAge(100);
                return true;
            }
            return e.getAge() != null && e.getAge() > 10;
        };
    }

谓词逻辑可无限套娃

public class Test {
    public static void main(String[] args) {


        List users = Arrays.asList(new User(12,"M"),new User(11,"W"));
    //        List user2 = users.stream().filter(e -> {
//            if(e.getAge() == null){
//                e.setAge(100);
//                return true;
//            }
//            return e.getAge() != null && e.getAge() > 10;
//        }).collect(Collectors.toList());
    List user2 = users.stream().filter(predicateTestAll()).collect(Collectors.toList());
        user2.stream().forEach(System.out::print);
}


    static Predicate predicateTest() {
        return e -> {
            if(e.getAge() == null){
                e.setAge(100);
                return true;
            }
            return e.getAge() != null && e.getAge() > 10;
        };
    }

    static Predicate predicateTest2() {
        return e -> e.getSex().equals("M") ;
    }
    
    static Predicate predicateTestAll() {
        return predicateTest().and(predicateTest2());
    }

}

基础操作总结

遍历

forEach 输出流中的元素

list.stream().forEach(System.out::println);

 

map

1.map 将流中的元素从一种格式转换为另外一种格式(类型)如 Integer  ->String 

stream.map(e -> Integer..parseInt(e))

2.mapToInt 将元素转为整型

Stream.of("a","b").mapToInt(String::length)

3.map与foreach有时候可以完成一样的功能,但是map操作如果是复杂操作的话(值得是没用方法引用),需要用return返回最终的结果元素,foreach不用。

//map
list.stream.map(e -> {
    e.setAge(1);
    return e;
}).collect(Collectors.toList());
//foreach
list.foreach(e -> {
    e.setAge(1);
})

flatMap与map

flatMap理解为,处理多个集合合并,或者一个元素处理后变成一个数组,最终结果是集合的集合(List>),数组中有数组,管道中有管道等多维的情况,此时要合成一个简单一维的字符串数组或者直接输出,此时单单map就有点复杂

List sss = Arrays.asList("abb","sss");
        List ss2 = sss.stream().map(e -> e.split("")).collect(Collectors.toList());
        ss2.stream().forEach(System.out::print);

此时打印出两个数组,但不是需要的值

[Ljava.lang.String;@6267c3bb[Ljava.lang.String;@533ddba

如果不用java8输出,那么需要两个for循环,采用java8 map的话就不能嵌套循环输出,所以此时考虑用flatMap扁平化(理解,把不同集合的元素 拍进同一个流中)

进一步简单理解为:flatMap 将集合的集合中的,集合元素转为流进行操作,然后合并多个流,汇聚成最终流。

List ssss = Arrays.asList("abb","sss");
        ssss.stream().flatMap(e -> Arrays.stream(e.split("")))
                .forEach(System.out::print);

//List s = ssss.stream().flatMap(e -> //Arrays.stream(e.split(""))).collect(Collectors.toList());

查找与匹配 

匹配

anyMatch() 是否存在至少一个符合要求的元素 存在返回true,不存在返回false

boolean result = list.stream().anyMatch(e -> e.getAge > 10);

allMatch() 是否所有元素都符合条件 是true 反之false

noneMatch() 是否不存在符合条件的元素 

查找

findFirst() 查找第一个元素

Optional result = list.stream().filter(e -> e.getAge > 10).findFirst();
User u = result.get();

isPresent() 是否存在

ifPresent() 如果存在做什么

orElse() 如果不存在做什么

元素连接joining

流中元素用指定符号连接或直接连接

//所有元素用逗号连接成字符串
String s = list.stream().collect(Collectors.joining(","));

规约reduce

目的:将一个集合转换为一个对象(如Integer,String等)

举例:

将集合中的元素累加,得出最终值

*reduce(初始值,累计操作器,合并器)

reduce(初始值,lambda表达式) 其中lambda表达式(a,b) -> {} 其中a表示当前结果,b为元素

累加

Integer sum = list.stream().reduce(0,(temp , e) -> temp + e);
//或
Integer sum2 = list.stream().reduce(0,Integer::sum);

 字符串拼接

String str = list.stream().reduce("",String::concat);

当设计到parallelStream()并行流时,reduce将有第三个参数,为合并器,将分组的结果进行合并

如此处将元素 1 2 3 4 分为两组1+2,3+4进行计算,最后通过合并器将两组结果合并为最终结果

Integer sum = list.parallelStream().reduce(0,Integer::sum,Integer::sum);

Optional

 个人理解:一个包装类,将结果进行包装,防止空指针异常

如果Optional包装后的对象,值存在,调用isPresent()方法返回true,调用get()方法返回该对象, 如果不存在抛异常

流操作过程的理解

流操作的过程可以分三部分(通俗比喻:冰川水入海流)

(1)源操作:河流源头,雪山、冰川、湖泊等  -》 数组,集合,行文本文件

(2)中间操作:河流河床经过的一些地方及人们对河流的影响及操作  -》(无状态操作)filter,map,flatmap,(有状态操作)limit,distinct,skip,sorted等

(3)终端操作:入海 -》.collect(Collectors.asList());

.collect(Collectors.toSet());

收集器Collectors
//收集为集合
.collect(Collectors.asList());
//收集为set
.collect(Collectors.toSet());
//收集成通用集合
.collect(Collectors.toCollection(linkedList::new));
.collect(Collectors.toCollection(linkedHashSet::new));
.collect(Collectors.toCollection(PriorityQueue::new));
//收集为数组
.toArray(String[]::new);
//收集为map 指定键值
.collect(Collectors.toMap(User::getId,User::getName));
//指定键,值为对象本身
.collect(Collectors.toMap(User::getId,User->User));
.collect(Collectors.toMap(User::getId, Function.identity()));//效果同上
//map中重复key的解决方法
//第二个key覆盖第一个key 或者 事先将充当key值得元素去重等
.collect(Collectors.toMap(User::getId, Function.identity(),(key1,key2)->key2));

分组收集groupingBy

(1)根据某一个字段值分组,并统计

//根据年龄分组,统计各个年龄对应多少人
Map m = list.stream() 
    .collect(Collectors.groupingBy(User::getAge,Collectors.counting()));

(2)多次分组嵌套

//先按班级分组,再按性别分组,统计每班男女各多少人
Map> m = list.stream()
    .collect(Collectors.groupingBy(User::getClass,                      
        Collectors.groupingBy(User::getSex,Collectors.counting())));

(3)自定义key值得分组

//统计已成年,未成年分别多少人,键为已成年,未成年
Map m =                
    games.stream().collect(Collectors.groupingBy(e -> {
                                if(e.getAge() > 18 ){
                                    return "已成年";
                                }else {
                                    return "未成年";
                                },Collectors.counting()));

 (3)键为日期字符串,对键进行排序最后有序存入map中

//数据源,键为日期字符串
Map map = Maps.newHashMap();
map.put("1-25",4L);
map.put("1-21",3L);
map.put("1-22",4L);

//时间排序且结果有序
Map result = Maps.newlinkedHashMap();
map.entrySet().stream().sorted(Map.Entry.comparingByKey())
    .forEachOrdered(e -> result.put(e.getKey(),e.getValue()));

//打印结果
result.entrySet().forEach(System.out::println);

聚合操作/统计

count() 计数

//通常与过滤一起使用
long count = list.stream().count();

sum()求和

int sum = list.stream().sum();

 average()求平均值

OptionalDouble average = list.stream().average();

max()/min() 最大值和最小值

int max = list.stream.max();

有状态操作与无状态操作

对于中间操作 有状态无状态的理解

无状态操作是对本身进行操作比如自身转换,过滤,与别人无关

有状态则需要参照前后元素位置改变等,如对比后排序,跳过,对比去重

limit(n)

取前n个元素

skip(n)

跳过前n个取后面元素

distinct()

去重 -》衍生自定义去重

去重拓展

sorted()

自然排序 -》衍生自定义排序

排序拓展

集合的常规排序

以前集合通过Collections.sort()来进行排序,通过传递排序规则来进行自定义排序

如list.sort(String.CASE_INSENSITIVE_ORDER) //不考虑大小写按字母表顺序排序

倒序排序:list.sort(Comparator.comparing(User::getAge)).reversed());

多个排序规则:list.sort(Comparator.comparing(User::getAge).thenComparingInt(User::getId));

java8 sorted自定义排序

前提:流中元素必须实现Comparable接口

(1) 自然升序 一般用于List,List

list.stream().sorted().collect(Collectors.toList());

(2)根据条件升序 List,根据实体中某个字段

list.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());

(3)自然降序

ist.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());

(4)根据条件降序

list.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList());

(5)多个字段排序

list.sorted(Comparator.comparing(User::getAge).thenComparing(User::getId)).collect(Collectors.toList());

(6)含空值排序

如果排序条件含有null的,可以排到最后,不处理的话会报空指针异常

list.stream().sorted(Comparator.comparing(User::getAge,Comparator.nullsLast(String::compareTo))).collect(Collectors.toList());

并行流

1.流的串行(sequential()默认)与并行(parallel())

之前的操作都为串行,加上.parallel()变为并行流

串行流:一个个处理,保证输入与输出顺序对应

并行流:并行处理,速度更快,但顺序改变(注意有状态的操作会收到影响,因为分组并行,与最终整体结果的处理会不一致)

不适合用并行流的情况:linkedList链表(区别ArrayList有下标方便并行时分组),阻塞队列,IO流等。适合:ArrayList,HashMap,数组

运行效率对比:

不能简单对比,并行流与cpu资源有关,且数据量越大,Stream流的执行效率越高,所以一般情况可能运行的速度 并行流大于for循环大于可能等于串行流

parallelStream() 与stream.parallel() 相同

2.使用并行流时候forEach()与forEachOrdered()的区别

forEach() 由于并行流分组处理,故输出不保证顺序

forEachOrdered() 按照元素输入的顺序进行输出

(后续完善更新中...)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/703792.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号