Java=JDK8新特性,Lambda表达式,Stream流

Lanbda表达式

Stream流

一。Lambda表达式

也可以成为闭包,推动jdk8发布的最重要的特性

Lambda允许把函数作为一个方法的参数-函数作为参数传递进方法中

使用Lambda 表达式可以使代码变的更加简洁紧凑

格式:

Lambda的标准格式:
	(参数列表)->{方法体;return 返回值;}
详情介绍:
	(参数列表) 相当于方法的参数,如果没有参数,那么只写小括号即可(小括号不能省略)
    ->: 固定用法,代码拿着前面的参数,去做什么事情
    {}: 大括号中先写计算过程,如果有返回值return 返回值;,如果没有返回值return语句可以省略    
//面向对象的格式
new Thread(new Runnable() {
	public void run() {
		System.out.println("执行了...");
	}
}).start();   
//Lambda的格式
new Thread(()->{System.out.println("执行了...");}).start();

Lambda的参数和返回值

public static void arraySort1(){
    //1.数组
    Integer[] nums = {4,5,61,7,8,9,34,56,345};
    //2.对数组排序(默认升序)
    //Arrays.sort(nums);
    //        Arrays.sort(nums, new Comparator<Integer>() {
    //            @Override
    //            public int compare(Integer o1, Integer o2) {
    //                //降序
    //                return o2-o1;
    //            }
    //        });
    //使用Lambda表达式修改上面冗余的代码
    Arrays.sort(nums,(Integer o1, Integer o2)->{return o2-o1;});

    //3.输出
    System.out.println(Arrays.toString(nums));
}

public static void main(String[] args) {
    //1.数组
    Dog[] dogs = new Dog[4];
    dogs[0] = new Dog(4,"jack",4);
    dogs[1] = new Dog(3,"mary",5);
    dogs[2] = new Dog(2,"ady",6);
    dogs[3] = new Dog(5,"hanmeimei",3);
    //2.排序
    //        Arrays.sort(dogs, new Comparator<Dog>() {
    //            @Override
    //            public int compare(Dog o1, Dog o2) {
    //                //按照狗的年龄降序
    //                return o2.age-o1.age;
    //            }
    //        });
    //使用Lambda表达式修改上面冗余的代码
    Arrays.sort(dogs,(Dog o1, Dog o2)->{return o2.age-o1.age;});

    //3.打印
    for (Dog dog : dogs) {
        System.out.println(dog);
    }
}

Lambda的省略格式

a.参数类型可以省略
b.如果参数只有一个,那么小括号可以省略
c.如果{}中的代码可以写成一句代码.那么{},return关键字和分号可以同时省略(不能省略某个)   
    
//体验一下Lambda表达式(函数式编程)优雅的写法
new Thread(()->{System.out.println("执行了...");}).start();
//省略格式
new Thread(()->System.out.println("执行了...")).start();  


//使用Lambda表达式修改上面冗余的代码
Arrays.sort(nums,(Integer o1, Integer o2)->{return o2-o1;});
//省略格式
Arrays.sort(nums,(o1,o2)-> o2-o1);


//使用Lambda表达式修改上面冗余的代码
Arrays.sort(dogs,(Dog o1, Dog o2)->{return o2.age-o1.age;});
//省略格式
Arrays.sort(dogs,(o1,o2)->o2.age-o1.age);

注意事项:

a.Lambda只能用于替换 有且仅有一个抽象方法的接口的匿名内部类对象,这种接口称为函数式接口
b.Lambda具有上下文推断的功能, 所以我们才会出现Lambda的省略格式  

二。Stream流

唯一缺点是:代码可读性不高

流Api的接口定义在java.util.stream包下。BaseStream是最基础的接口,但是最常用的是BaseStream的一个子接口--Stream,基本上绝大多数的流式处理都是在Stream接口上定义的

count()  返回流中的元素个数  终端操作

distinct() 去除流中的重复元素, 中间操作

filter()  返回一个满足指定条件的流  中间操作

forEach()  遍历流中的每一个元素,执行action操作  终端操作

limit()  获取流中前maxsize元素  中间操作

map() 对流中的元素调用mapper方法,产生包中含这些元素的新的流

skip()

max()终端操作

min()  终端操作

sorted() 排序,按指定规则  终端操作

sorted()终端操作

这里的 filter map skip 都是在对函数模型进行操作,集合元素并没有真正被处理。只有当终结方法
count 执行的时候,整个模型才会按照指定策略执行操作。而这得益于 Lambda 的延迟执行特性。
备注: “Stream 其实是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身并不存储任何
元素(或其地址值)。

引入:传统的集合操作

public class TestDemo01 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

        //1. 首先筛选所有姓张的人;
        ArrayList<String> zhangs = new ArrayList<String>();
        for (String name : list) {
            if (name.startsWith("张")){
                zhangs.add(name);
            }
        }

        //2. 然后筛选名字有三个字的人;
        ArrayList<String> threes = new ArrayList<String>();
        for (String zhang : zhangs) {
            if (zhang.length() == 3) {
                threes.add(zhang);
            }
        }

        //3. 最后进行对结果进行打印输出。
        for (String three : threes) {
            System.out.println(three);
        }
    }
}

循环遍历的弊端分析

Lambda注重于做什么,传统的面向对象注重于怎么做??
    
 for (String three : threes) { //这就是传统的面向对象注重怎么做,就是形式
     System.out.println(three);//这里才是我们注重做什么
 }    
为了解决面向对象语法复杂形式,我们引入一种新的技术:Stream 流式思想

体验Stream的优雅写法

体验一下Stream流的优雅代码
list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s-> System.out.println(s));

1、获取流的方式

a.Collection集合获取流
    Stream<E> s = 集合对象.stream();

b.Map集合不能直接获取流,但是可以间接获取流
    map.keySet().stream(); 获取map的键流
    map.values().stream(); 获取map的值流
    map.entrySet().stream(); 获取Map的键值对流
    
c.数组获取流
    Stream<数据中元素的类型> s = Stream.of(数据类型... 变量名);
    
public class StreamDemo01 {
    public static void main(String[] args) {
        //获取各种容器的流
        //1.单列集合
        ArrayList<String> arr = new ArrayList<String>();
        //....添加数据
        Stream<String> s1 = arr.stream();

        //2.双列集合
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        Stream<String> keyStream = map.keySet().stream(); //键流
        Stream<Integer> valueStream = map.values().stream();//值流
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();//键值对流
        
        //3.数组
        Integer[] nums = {10,20,30,40};
        Stream<Integer> s2 = Stream.of(nums);
        Stream<Integer> s3 = Stream.of(11,22,33,44);
    }
}

Stream流中的常用方法

逐个处理:forEach

//1.获取到一个流
Stream<String> s1 = Stream.of("jack", "tom", "rose", "lilei", "jerry");
//2.foreach 逐一处理
//使用匿名内部类
//        s1.forEach(new Consumer<String>() { //
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
//使用Lambda
//        s1.forEach((String s)->{System.out.println(s);});
//使用Lambda的省略格式
s1.forEach(s -> System.out.println(s));

统计个数:count

//3.count 统计个数
long count = s1.count();
System.out.println("流中有多少个元素:"+count);

过滤filter

//4.filte 过滤方法
//匿名内部类
//        Stream<String> s2 = s1.filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                //我们只想要 长度大于4的字符串
//                return s.length() > 4;
//            }
//        });

//Lambda
Stream<String> s2 = s1.filter(s -> s.length() > 4);

System.out.println(s2.count());

取前几个:limit

//5.limit 取前几个
Stream<String> s3 = s1.limit(3);
s3.forEach(s-> System.out.println(s));

跳过前几个:skip

//6.skip 跳过前几个
Stream<String> s4 = s1.skip(2);
s4.forEach(s-> System.out.println(s));

映射方法:map

map方法是将流中每个元素,经过某种算法,变成另外一个元素
//7.map 映射
//        Stream<Integer> s5 = s1.map(new Function<String, Integer>() {
//            @Override
//            public Integer apply(String s) {
//                return s.length();
//            }
//        });
//Lambda改写
Stream<Integer> s5 = s1.map(s->s.length());

s5.forEach(s-> System.out.println(s));    

静态方法合并流:concat

public static Stream<T> concat(Stream<T> s1,Stream<T> s2);

//8.concat 静态方法,合并两个流
Stream<String> ss1 = Stream.of("jack","rose");
Stream<String> ss2  = Stream.of("tom","lucy");
//静态方法
Stream<String> sss = Stream.concat(ss1,ss2);
sss.forEach(s-> System.out.println(s));

注意:
	a.如果是两个以上流的合并,需要多次两两合并
    b.如果两个流的泛型不一致也可以合并,合并之后新流的泛型是他们共同的父类(不知道其父类,写Object) 
集合元素的处理(Stream方式)

//使用传统集合遍历方式
public class StreamDemo04 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");
        //按照求操作集合(使用传统的for循环)
//        1. 第一个队伍只要名字为3个字的成员姓名;
        ArrayList<String> one1 = new ArrayList<String>();
        for (String name : one) {
            if (name.length() == 3) {
                one1.add(name);
            }
        }
//        2. 第一个队伍筛选之后只要前3个人;
        ArrayList<String> one2 = new ArrayList<String>();
        for (int i = 0; i < 3; i++) {
            String name = one1.get(i);
            one2.add(name);
        }


//        3. 第二个队伍只要姓张的成员姓名;
        ArrayList<String> two1 = new ArrayList<String>();
        for (String name : two) {
            if (name.startsWith("张")){
                two1.add(name);
            }
        }
//        4. 第二个队伍筛选之后不要前2个人;
        ArrayList<String> two2 = new ArrayList<String>();
        for (int i = 2; i < two1.size(); i++) {
            String name = two1.get(i);
            two2.add(name);
        }

//        5. 将两个队伍合并为一个队伍;
        ArrayList<String> all = new ArrayList<String>();
//        all.addAll(one2);
//        all.addAll(two2);
        for (String name : one2) {
            all.add(name);
        }
        for (String name : two2) {
            all.add(name);
        }

//        6. 根据姓名创建 Person 对象;
        ArrayList<Person> persons = new ArrayList<Person>();
        for (String name : all) {
            Person p = new Person(name);
            persons.add(p);
        }

//        7. 打印整个队伍的Person对象信息。
        for (Person person : persons) {
            System.out.println(person);
        }

    }
}

使用Stream流的方式
public class StreamDemo05 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");
        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");
//        1. 第一个队伍只要名字为3个字的成员姓名;
//        2. 第一个队伍筛选之后只要前3个人;
        Stream<String> s1 = one.stream().filter(s -> s.length() == 3).limit(3);

//        3. 第二个队伍只要姓张的成员姓名;
//        4. 第二个队伍筛选之后不要前2个人;
        Stream<String> s2 = two.stream().filter(s -> s.startsWith("张")).skip(2);

//        5. 将两个队伍合并为一个队伍;
        Stream<String> ss = Stream.concat(s1, s2);

//        6. 根据姓名创建 Person 对象; string -- person
        Stream<Person> ps = ss.map(s -> new Person(s));

//        7. 打印整个队伍的Person对象信息
        ps.forEach(p-> System.out.println(p));
    }
}
    

函数拼接和终结

函数拼接方法: 由于这种方法返回的还是流对象,故支持链式编程
	调用该方法之后,返回还是一个流对象
	有:filter,limit,skip,map,concat
终结方法: 由于终结方法没有返回或者返回的不是流,那么不支持链式编程,并且当某个流调用终结方法之后,该流就关闭了,不能继续调用其他任何方法
	调用该方法之后,返回值不是流或者无返回值
	有:forEach,count

收集Stream

可以把流收集到集合中,调用流的collect方法即可
可以把流收集到数组中,调用流的toArray方法即可
public class StreamDemo03 {
    public static void main(String[] args) {
        //收集流中的结果
        Stream<Integer> s1 = Stream.of(1,2,3,4,5);
        //....对流进行各种操作
        //1.将流中的结果收集到集合中
        List<Integer> list = s1.collect(Collectors.toList());
        System.out.println(list);

        Set<Integer> set = s1.collect(Collectors.toSet());
        System.out.println(set);
        //2.将流中的结果收集到数组中
        Object[] objs = s1.toArray();
        for (Object obj : objs) {
            System.out.println(obj);
        }
    }
}
注意:
	a.一个流只能收集一次(第二次收集会报错!!!)
    b.如果收集到数组中某个收集到Object数组    
    

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

补充:

数据查找:

allMatch()Stream提供的方法,该方法判断流中的元素是否全部符合某一个条件,返回结果为boolean值,如果是,返回true,否则flase

anyMatch()Stream提供的方法,该方法会判断流中的元素是否有符合某一条件,只要有一个元素符合条件就返回true,如果没有符合条件的元素就返回false

noneMathch():stream接口提供的方法》  该方法会判断流中所有的元素是否都不符合某一个条件,这个方法的逻辑和 allmatch正好相反

findFirst()stream接口提供的方法,这个方法会返回符合条件的第一个元素、这个方法返回值不是boolean,而是一个optional对象

Collectors类:

https://www.jianshu.com/p/7eaa0969b424

https://blog.csdn.net/Alice_qixin/article/details/87169586

将流中的数据转成集合类型: toList、toSet、toMap、toCollection
将流中的数据(字符串)使用分隔符拼接在一起:joining
对流中的数据求最大值maxBy、最小值minBy、求和summingInt、求平均值averagingDouble
对流中的数据进行映射处理 mapping
对流中的数据分组:groupingBy、partitioningBy
对流中的数据累计计算:reducing
 
 请使用Lambda表达式调用Collections的sort()方法,可以实现对一个List<String>集合进行:降序排序。
	编写main()方法,在main()中按以下步骤编写代码:
	1. 定义一个List<String>集合,并存储以下数据:
			“cab”
			“bac”
			“acb”
			“cba”
			“bca”
			“abc”
	2. 使用Lambda表达式调用Collections的sort()方法对集合进行降序排序。
	3. 排序后向控制台打印集合的所有元素。

public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        strings.add("cab");
        strings.add("bac");
        strings.add("acb");
        strings.add("cba");
        strings.add("bca");
        strings.add("abc");
        //
        Collections.sort(strings,(o1,o2)->o2.compareToIgnoreCase(o1));
        System.out.println(strings);

    }

关于其他:

https://blog.csdn.net/Alice_qixin/article/details/87169586

https://www.jianshu.com/p/232fc8acedba

https://blog.csdn.net/qq_20989105/article/details/81234175

https://blog.csdn.net/qq_37415950/article/details/80183654

发布了117 篇原创文章 · 获赞 20 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/u010581811/article/details/104968678