Java的 不可变集合,Stream流,方法引用

不可变集合详解(map的ofEntries方法,copyOf方法)

  • 不可变集合:不能被修改的集合
    长度和内容都不能改变

  • 创建不可变集合的应用场景:
    不想让别人修改集合中的内容,当别人拿到这个不可变集合时,只能进行查找工作,不能修改,删除,添加元素的。

    例如:斗地主时每张牌都不可变,出牌的规则必须按照某一规则执行,再例如某些介绍信息,在这里插入图片描述

  • 创建不可变集合的书写格式
    在List,Set,Map接口中都存在静态的of方法,可以获取一个不可变的集合

方法名说明
static< E > List< E >of(E…elements)创建一个具有指定元素的List集合对象
static< E > Set< E >of(E…elements)创建一个具有指定元素的Set集合对象
static< K,V > Map< K,V >of(E…elements)创建一个具有指定元素的Map集合对象

注:用以上方法创建的集合不能添加,修改,删除

public class One {
    public static void main(String[] args) {
        //这个List集合不可修改,添加,删除元素。但是可以进行查询遍历
        List<String>list=List.of("张三","sss","ccc","11s");
        //同理,也可以创建不可变的Set集合和Map集合
        
        //注意,Set集合的元素是唯一的,所以在创建Set集合时一定要保证元素的唯一性
        //Set<String>set=set.of("111","sss","ccc","11s");
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("----------------------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("----------------------");
        Iterator<String>it= list.iterator();
        while(it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }
    }
}
//Map集合
public class One {
    public static void main(String[] args) {
        //这个集合不可修改,添加,删除元素。但是可以进行查询遍历
        //Java会把第一对参数分别看作键和值,
        //同理,第二对,第三对也是如此

        //细节:
        // 1.键是不能重复的
        // 2.Map的of方法,参数是有上限的,最多只能传递20个参数,即10个键值对
        Map<String, String>map = Map.of(
                "aa", "11",
                "bb", "22",
                "cc", "33",
                "dd", "44",
                "ee", "55",
                "ff", "66",
                "gg", "77");

        Set<String> strings = map.keySet();
        for (String s : strings) {
            String value=map.get(s);
            System.out.println(s+"="+value);
        }
        System.out.println("---------------------------");
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String s=entry.getKey();
            String value=entry.getValue();
            System.out.println(s+"="+value);
        }
    }
}
  • map的ofEntries方法
//map的ofEntries方法
public class Two {
    public static void main(String[] args) {
        //这个Map集合的键值对超过10个
        HashMap<String,String>hm=new HashMap<>();
        hm.put("aaa","111");
        hm.put("bbb","121");
        hm.put("ccc","131");
        hm.put("ddd","141");
        hm.put("eee","151");
        hm.put("fff","161");
        hm.put("ggg","171");
        hm.put("hhh","181");
        hm.put("iii","191");
        hm.put("jjj","211");
        hm.put("kkk","221");
        //可以利用上面的数据获取一个不可变集合
        //先获取一个Set集合,存储着所有的键值对对象
        Set<Map.Entry<String, String>> entries = hm.entrySet();
        //把entries变成一个数组
        //这一步创建了一个Map.Entry类型的数组
        Map.Entry[]arr1=new Map.Entry[0];
        //这一步把Set集合entries变成了一个数组
        //toArray的特性:toArray方法底层会比较集合和数组长度两者的大小
        //如果集合的长度>数组的长度,数据此时在集合中放不下,此时会根据实际数据的个数重新创建数组
        //如果集合的长度<=数组的长度,数据此时在集合中能放下,此时就不会创建新的数组,而是使用老数组
        Map.Entry[] arr2 = entries.toArray(arr1);
        //此时就可以使用ofEntries方法,由于ofEntries方法的参数是一个可变参数,
        //而可变参数在底层又是一个数组,所以可以直接传递数组
        //这个map集合就是不可变的map集合
        Map map1 = Map.ofEntries(arr2);

        //上述代码的简化,这行代码与上述代码表达的意思是一样的
        Map<Object, Object> map2 = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));

        //还有更简单的,在Jdk10出现的copyOf方法
        //copyOf方法会在底层进行一个判断,如果是不可变的集合,就直接返回原集合
        //如果是可变的集合,就会通过上述代码把集合变为不可变集合
        Map<String, String> map3 = Map.copyOf(hm);

        //这里的map1,2,3都是不可变集合
        
    }
}
  • 小结
    在这里插入图片描述

Stream流

Stream的基本概念和创建

-Stream流的思想
就像工厂的流水线,通过许多过滤的操作才能输出
在这里插入图片描述

  • Stream流的作用
    结合了Lambda表达式,简化集合,数组的操作

  • Stream流的使用步骤
    1.先得到一条Stream流(流水线),并把数据放上去
    2.利用Stream流的API进行各种操作

    • 这些操作分为中间方法和终结方法
    • 例如:
    • 过滤,转换等,属于中间方法,方法调用完毕后,还可以调用其他方法
    • 统计,打印等就属于终结方法,最后一步,调用完毕后,不能调用其他方法

    要细分的话,就可以分为三步
    在这里插入图片描述

  • 得到Stream流的方法

获取方式方法名说明
单列集合default Stream< E >stream()Collection中的默认方法
双列集合无法直接使用Stream流
数组public static < T >Stream< T >stream(T[]array)Arrays工具类的静态方法
一堆零散数据public static < T >Stream< T >of(T…values)Stream接口中的静态方法

双列集合要想使用Stream流,必须先使用ketSet或entrySet先把双列数组转成单列数组,然后才能使用

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class testOne {
    public static void main(String[] args) {
        //单列集合获取Stream流
        ArrayList<String>s=new ArrayList<>();
        Collections.addAll(s,"a","b","c","d");
        //直接使用方法获取
        Stream<String> stream1 = s.stream();
        //可以用forEach的方法进行遍历
        stream1.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        //简单的写法就是
        s.stream().forEach(b-> System.out.println(b));


        //双列集合获取Stream流
        HashMap<String,String>hm=new HashMap<>();
        hm.put("aaa","111");
        hm.put("bbb","211");
        hm.put("ccc","311");
        hm.put("ddd","411");
        //第一种先变成单列集合
        Set<String> strings = hm.keySet();
        //再使用单列集合获取Stream流的方法
        Stream<String> stream2 = strings.stream();
        stream2.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        strings.stream().forEach(b-> System.out.println(b));


        //数组获取Stream流
        int[]arr={1,2,3,4,5,6};
        //Arrays.stream(arr)是获取arr数组的Stream流,把数据放到流水线上
        //后面的forEach就是打印,遍历数组
        Arrays.stream(arr).forEach(b-> System.out.println(b));


        //零散数据获取Stream流
        //前提条件,数据必须是同一类型
        Stream.of("a","b","v","d","g","w").forEach(b-> System.out.print(b));
    }
}

注意:
Stream接口中of的细节
of方法中的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
但是传递的数组必须是引用数据类型的,如果传递基本数据类型,就会把整个数组当成一个元素,放到Stream流中

Stream的中间方法

常见的中间方法

方法名说明
Stream< T >filter(Predicate<? super T> predicate)过滤
Stream< T > limit(long maxSize)获取前几个元素
Stream< T >skip(long n)跳过前几个元素
Stream< T >distinct()元素去重,依赖(hashCode和equals方法)
static< T >Stream< T >concat(Stream a,Stream b)合并a和b两个流为一个流
Stream< R >map(Function< T,R >mapper)转换流中的数据类型

注意:使用distinct时,如果是自定义类型,需要重写hashCode和equals方法,使用concat方法时,尽可能使两个流的数据类型保持一致,如果不一致,合并出的新流的数据类型就是a,b两个流数据类型的父类
在这里插入图片描述
Stream流只能使用一次,所以不用变量记录,直接使用链式编程就行

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class testTwo {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"张1","张2","张3","张4",
        "李5","张6","刘7","张8","王6");

        //filter过滤
        list.stream().filter(new Predicate<String>() {
            @Override
            //这里的s表示Stream流中的数据
            public boolean test(String s) {
                //返回值为true,表示当前数据留在Stream流中
                //返回值为false,表示数据舍弃不要
                return s.startsWith("张");
            }
        }).forEach(s-> System.out.println(s));
        //可以做简化,下面的就是简化版本
        list.stream().
        filter(s->s.startsWith("张")).
        forEach(s-> System.out.println(s));
        //注意,这里的list.stream()创建的Stream流只能使用一次,
        //所以不要用变量记录,直接使用链式编程就行


        System.out.println("_________________________");
        //limit,获取前几个元素
        //注意,这里的参数代表这要获取的元素个数,而不是索引
        list.stream().
                limit(3).
                forEach(s-> System.out.print(s+" "));//张1 张2 张3


        System.out.println("");
        System.out.println("_________________________");
        //skip,跳过前几个元素,获取到后面的元素
        list.stream().
                skip(3).
                forEach(s-> System.out.print(s));//张4 李5 张6 刘7 张8 王6


        System.out.println("");
        System.out.println("_________________________");
        //distinct,元素去重,依赖(hashCode和equals方法)
        ArrayList<String>list1=new ArrayList<>();
        Collections.addAll(list1,"张1","张1","张1","张1",
        "李5","张6","刘7","张8","王6");
        list1.stream().
                distinct().
                forEach(s-> System.out.print(s));//张1 李5 张6 刘7 张8 王6

        System.out.println("");
        System.out.println("_________________________");
        //concat,合并a和b两个流为一个流
        ArrayList<String>list2=new ArrayList<>();
        Collections.addAll(list2,"张10","王106");
        //尽可能让数据类型保持一致
        Stream.//这里concat的参数是Stream流
                concat(list.stream(),list2.stream()).
                forEach(s-> System.out.println(s));

        System.out.println("");
        System.out.println("_________________________");
        //map,转换流中的数据类型
        ArrayList<String>list3=new ArrayList<>();
        Collections.addAll(list3,"张-10","张-11","张-5","张-13","张-12");
        //通过map可以只获取list3数据的一部分,
        //例如,只获取上面数据的数字,不获取文字

        //Function参数的意思
        //第一个代表流中原本的数据类型
        //第二个代表要装换成的数据类型
        list3.stream().map(new Function<String, Integer>() {
            @Override
            //apply的形参s依次表示流中的每一个数据
            //返回值表示转换之后的数据
            public Integer apply(String s) {
                //正则表达式,把一个字符串切割成两个存储到数组中
                String[]arr=s.split("-");
                //例如:张-10,arr[0]表示 张,arr[1]表示10
                String s1 = arr[1];
                int i = Integer.parseInt(s1);
                return i;
            }
        }).forEach(s-> System.out.println(s));

        //简化版
        list3.stream().map(s->Integer.
        parseInt(s.split("-")[1])).
        forEach(s-> System.out.println(s));
    }
}

Stream流的终结方法

方法名说明
void forEach(Consumer action)遍历
long count()统计,统计流中的数据
toArray()收集流中的数据,放到数组中
collect(Collector collector)收集流中的数据,放到集合中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.IntFunction;

public class testThree {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        Collections.addAll(list,"张1","张2","张3","张4","李5","张6","刘7","张8","王6");
        //forEach,遍历
        //匿名内部类,可以直接写成lambda表达式的形式
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        list.stream().forEach(s-> System.out.println(s));
        System.out.println("____________________________");

        //count,统计
        //统计流中元素的个数
        System.out.println(list.stream().count());

        //toArray,	收集流中的数据,放到数组中
        //有两个参数的,一个是空参,会把流中的数据放到一个类型为Object的数组中
        System.out.println(Arrays.toString(list.stream().toArray()));

        //另一个是带参数的toArray
        //参数是IntFunction,作用:创建一个指定类型的数组
        //toArray方法的底层:会依次得到流里面的每一个数据,并把数据放到数组中
        //toArray方法的返回值:是一个装着流里面所有数据的数组
        //IntFunction的泛型:? extends Object[]:表示一个具体类型的数组
        String[] arr = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            //apply形参:流中数据的个数,要跟数组的长度一致
            //apply的返回值:具体类型的数组
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(arr));
        //lambda表达式
        String[] arr2 = list.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(arr2));
    }
}
  • collect,收集方法,收集流中的数据,放到集合中(List,Set,Map)
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class testFour {
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        Collections.addAll(list,"张1-男-10","张2-女-11","张3-男-5","张4-女-13","张5-男-12");
        //收集到List集合中,把所有的男性收集
        List<String> collect1 = list.stream().//这一步是过滤男性
                filter(s -> "男".equals(s.split("-")[1])).
                //这一步就是把过滤后的数据收集到集合中
                //Collectors是Stream流的一个工具类,
                //toList就是创建一个ArrayList集合,把收集的数据放到ArrayList集合中
                        collect(Collectors.toList());
        System.out.println(collect1);
        //收集到Set集合中,把所有的男性收集
        //同理
        Set<String> collect2 = list.stream().
                filter(s -> "男".equals(s.split("-")[1])).
                collect(Collectors.toSet());
        System.out.println(collect2);
        //收集到Set集合与List集合的区别
        //与Set集合与List集合的区别一样,Set集合没有重复元素
        //而List集合可以有重复元素








        //收集到Map集合中
        //注意:谁作为键,谁作为值,还要注意:如果把流中的元素收集到Map集合中,键不能重复,否则会报错
        //把所有的男性收集,键:姓名,值:年龄
        Map<String, Integer> map;
        map = list.stream().
                filter(s -> "男".equals(s.split("-")[1])).
                //这里的toMap里的参数就是 键的规则和值的规则
                /*
                *   toMap:参数1表示键的生成规则
                *          参数2表示值的生成规则
                *   参数一:
                *       这里Function的形参,第一个参数表示流中数据类型,
                        第二个参数表示Map集合中键的数据类型
                *   参数二:
                *       这里Function的形参,第一个参数表示流中数据类型,
                        第二个参数表示Map集合中值的数据类型
                * */
                //这里Function的形参,第一个参数表示流中数据类型,
                //第二个参数表示Map集合中键的数据类型
              collect(Collectors.toMap(new Function<String, String>() {
                    @Override
                    //这里apply的形参s表示流里的每一个数据
                    //方法体就是生成键的代码
                    //返回值已经生成的键
                    public String apply(String s) {
                        return s.split("-")[0];
                    }
                    //这里Function的形参,第一个参数表示流中数据类型,
                    //第二个参数表示Map集合中值的数据类型
                }, new Function<String, Integer>() {
                    @Override
                    //这里apply的形参s表示流里的每一个数据
                    //方法体就是生成值的代码
                    //返回值已经生成的值
                    public Integer apply(String s) {
                        return Integer.parseInt(s.split("-")[2]);
                    }
                }));
        System.out.println(map);
        //简化版
        Map<String, Integer> map2 = list.stream().
        filter(s -> "男".equals(s.split("-")[1])).
        collect(Collectors.toMap(
                s -> s.split("-")[0],
                s -> Integer.parseInt(s.split("-")[2]))
        );
        System.out.println(map2);
    }
}

Stream流的小结

在这里插入图片描述

综合练习

在这里插入图片描述

public class testFive {
    public static void main(String[] args) {
        ArrayList<Integer>list=new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
        Integer[] arr1 = list.stream().filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 2 == 0;
            }
        }).toArray(new IntFunction<Integer[]>() {
            @Override
            public Integer[] apply(int value) {
                return new Integer[value];
            }
        });
        System.out.println(Arrays.toString(arr1));
    }
}
//简化版
public class testFive {
    public static void main(String[] args) {
        ArrayList<Integer>list=new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
        Integer[] arr1 = list.stream().filter(s->s%2==0).
        toArray(value->new Integer[value]);
        System.out.println(Arrays.toString(arr1));
    }
}

在这里插入图片描述

public class testSix {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"zhangsan 23","lisi 24",
        "wangwu 25","wangliu 26","wangqi 21");
        Map<String, Integer> map = list.stream().
                filter(s -> Integer.parseInt(s.split(" ")[1]) >= 24).
                collect(Collectors.toMap(new Function<String, String>() {
                    @Override
                    public String apply(String s) {
                        return s.split(" ")[0];
                    }
                }, new Function<String, Integer>() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s.split(" ")[1]);
                    }
                }));
        System.out.println(map);
    }
}
//简化版
public class testSix {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"zhangsan 23","lisi 24",
        "wangwu 25","wangliu 26","wangqi 21");
        Map<String, Integer> map = list.stream().
                filter(s -> Integer.parseInt(s.split(" ")[1]) >= 24).
                collect(Collectors.toMap(
                        s -> s.split(" ")[0],
                        s->Integer.parseInt(s.split(" ")[1])
                ));
        System.out.println(map);

    }
}

在这里插入图片描述

public class testSeven {
    public static void main(String[] args) {
        ArrayList<String>list1=new ArrayList<>();
        ArrayList<String>list2=new ArrayList<>();
        Collections.addAll(list1,"张三,23","张德华,24",
        "张顺飞,25","电棍,26","张飞,27","铸币,27");
        Collections.addAll(list2,"杨月,23","杨玉莹,24",
        "杨志,25","杨柳燕,26","杨鸟,27","兲,27");
        //这里通过过滤和limit,skip,来满足要求
        Stream<String> limit1 = list1.stream().
        filter(s -> s.split(",")[0].length() == 3).
        limit(2);
        Stream<String> limit2 = list2.stream().
        filter(s -> s.split(",")[0].startsWith("杨")).
        skip(1);
        //合并上面两个流
        Stream<String> concat = Stream.concat(limit1, limit2);
//        concat.forEach(s-> System.out.println(s));
//使用Stream流时似乎不能对同一个Stream流使用多个forEach方法

        //将演员信息转换成Actor对象,需要用到类型转换  即名为map的中间方法
        //创建一个list集合用来存储Actor对象
        ArrayList<Actor>actorsList=new ArrayList<>();
        //使用map方法将刚才合并出的新Stream流的元素类型转换成Actor对象
        concat.map(new Function<String, Actor>() {
            @Override
            //s代表Stream流中的元素
            public Actor apply(String s) {
                Actor actor=new Actor();
                actor.setName(s.split(",")[0]);
                actor.setAge(Integer.parseInt(s.split(",")[1]));
                return actor;
            }
        }).forEach(new Consumer<Actor>() {
            @Override
            public void accept(Actor actor) {
                actorsList.add(actor);
            }
        });
        for (Actor actor : actorsList) {
            System.out.println(actor.getName()+" "+actor.getAge());
        }

    }
}

使用Stream流时似乎不能对同一个Stream流使用多个forEach方法

方法引用

方法引用的基本概念和使用

分成两个词语理解:方法和引用
方法:就是以前学习的方法
引用:把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
例如:Arrays.sort(arr,排序规则)这里的排序规则就可以直接使用方法引用

使用方法引用的条件:
1.引用处必须是函数式接口
2.被引用的方法必须已经存在
3.被引用的方法的形参和返回值需要跟抽象方法保持一致
在这里插入图片描述
4.被引用方法的功能要满足当前的需求

  • 匿名内部类,lambda表达式,方法引用的对比
import java.util.Arrays;
import java.util.Comparator;

public class testOne {
    public static void main(String[] args) {
        Integer[]arr={3,5,4,1,6,2};
        //匿名内部类
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(Arrays.toString(arr));
        System.out.println("______________________________");
        //lambda表达式
        Arrays.sort(arr,(Integer o1,Integer o2)->{return o2-o1;});
        System.out.println(Arrays.toString(arr));
        //lambda简化
        Arrays.sort(arr,(o1, o2)->o2-o1);
        System.out.println(Arrays.toString(arr));

        //方法引用
        //testOne::subtraction表示,引用testOne中的subtraction方法
        //下面这一句就表示,引用testOne中的subtraction方法,
        //把这个方法当作抽象方法的方法体
        Arrays.sort(arr,testOne::subtraction);
        System.out.println(Arrays.toString(arr));
    }
    //注意,这里被引用的方法可以是java已经写好的,也可以是第三方的工具类
    public static int subtraction(int num1,int num2){
        return num2-num1;
    }
}
  • 小结
    在这里插入图片描述

方法引用的分类

主要分为三类
在这里插入图片描述

1.引用静态方法
2.引用成员方法
3.引用构造方法

引用静态方法

格式:类名::方法名
例如:Integer::parseInt
在这里插入图片描述

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;

public class testTwo {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"1","2","3","4","5");
        //不使用方法引用
        list.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        }).forEach(s-> System.out.println(s));
        //方法引用
        list.stream().map(Integer::parseInt).forEach(s-> System.out.println(s));
    }
}
引用成员方法

格式:对象::成员方法
引用成员方法时,有三种情况,
1.其他类(引用其他类的成员方法)格式:其他类对象::方法名
2.本类:this::方法名(引用处不能是静态方法)
3.父类:super::方法名(引用处不能是静态方法)

  • 引用其他类的成员方法
    在这里插入图片描述
//StringOperation类
public class StringOperation {
    public boolean stringJudge(String s){
        return s.startsWith("张")&&s.length()==3;
    }
}


//test类
public class testThree {
    public static void main(String[] args) {
        /*
        *  集合中有一些名字,要求:只要张开头的,而且名字是三个字的
        *  数据:"张一","张三十","张德哈","张无忌","张飞将","张六","张三"
        * */
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"张一","张三十",
        "张德哈","张无忌","张飞将","张六","张三");
        //使用Stream流
        list.stream().
        filter(s -> s.startsWith("张")).
        filter(s -> s.length()==3).
        forEach(s -> System.out.println(s));
        //使用方法引用(其他类)
        list.stream().
        //这里先创建一个其他类的对象,然后使用方法引用
        filter(new StringOperation()::stringJudge).
        forEach(s -> System.out.println(s));

		//如果是本类的方法
		//就是这样,但是会有报错
		//list.stream().
        //filter(this::stringJudge).//这里报错,因为static中没有this
        //forEach(s -> System.out.println(s));
        
        //要想在static中引用本类方法
       	//就是这样
       	list.stream().
        //这里先创建一个本类的对象,然后使用方法引用
        filter(new testThree()::stringJudge).
        forEach(s -> System.out.println(s));
    }
    public boolean stringJudge(String s){
        return s.startsWith("张")&&s.length()==3;
    }
}
  • 引用本类和父类的成员方法
    本类:this::方法名
    父类:super::方法名

有个细节:就是引用处不能是静态方法,像上述代码那样

引用构造方法

格式:类名::new
例如:Student::new

引用构造方法的目的:创建对象 在这里插入图片描述

//Student类
    private String name;
    private int age;

    public Student() {
    }
    //这个构造方法是为了匹配testFour中apply方法的参数所构建的
    //public Student apply(String s)
    /*  1.引用处必须是函数式接口
        2.被引用的方法必须已经存在
        3.被引用的方法的形参和返回值需要跟抽象方法保持一致
        4.被引用方法的功能要满足当前的需求
    * */
    public Student(String s){
        this.name = s.split(",")[0];
        this.age = Integer.parseInt(s.split(",")[1]);
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }



//test类
public class testFour {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"张三,11",
                "张四,19","张里三,31","张而三,21",
                "张无三,51","张有三,13","张对三,12");
        /*  1.引用处必须是函数式接口
            2.被引用的方法必须已经存在
            3.被引用的方法的形参和返回值需要跟抽象方法保持一致
            4.被引用方法的功能要满足当前的需求**/
        //常规的代码
        List<Student> newList = list.stream().
        map(new Function<String, Student>() {
            @Override
            public Student apply(String s) {
                String name = s.split(",")[0];
                int age = Integer.parseInt(s.split(",")[1]);
                return new Student(name, age);
            }
        }).collect(Collectors.toList());
        //使用方法引用的代码
        List<Student> newList2 = list.stream().
        map(Student::new).
        collect(Collectors.toList());
        System.out.println(newList2);
    }
}
其他的调用方式

1.使用类名引用成员方法
2.引用数组的构造方法

使用类名引用成员方法(可以多看两遍)
  • 使用类名引用成员方法独有的规则:
    1.引用处必须是函数式接口
    2.被引用的方法必须已经存在
    3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
    4.被引用方法的功能需要满足当前的要求

抽象方法形参的详解:

  • 第一个参数:(即第一个参数决定了可以引用哪些类的成员方法)
    表示被引用方法的调用者,决定了可以引用哪些类中的抽象方法,在Stream流中,第一个参数一般都表示流里面的每一个数据。
    假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类的方法

  • 第二个参数到最后一个参数:
    跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

格式:类名::成员方法名
例子:String::substring
在这里插入图片描述

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;

public class testFive {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc","ddd");
        //常规方法
        list.stream().map(new Function<String, String>() {
            @Override
            public String apply(String s) {//只有一个形参
                return s.toUpperCase();
            }
        }).forEach(s-> System.out.println(s));

        //使用类名引用成员方法
        //拿着流里面每一个数据,去调用String类中的toUpperCase方法
        //方法的返回值就是转换之后的结果	
        list.stream().
        map(String::toUpperCase).
        forEach(s -> System.out.println(s));
    }
}

这种方式有一定的局限性:
不能引用所有类中的成员方法
跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法

引用数组的构造方法

格式:数据类型[]::new
例子:int[]::new

注意:数组的类型需要跟流中数据类型保持一致
目的:就是创建一个指定类型的数组
在这里插入图片描述

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;

public class testSix {
    public static void main(String[] args) {
        ArrayList<Integer>list=new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6);
        //常规代码
        Integer[] arr1 = list.stream().toArray(new IntFunction<Integer[]>() {
            @Override
            public Integer[] apply(int value) {
                return new Integer[value];
            }
        });
        System.out.println(Arrays.toString(arr1));
        //引用数组的构造方法
        //这里的arr2中的数据与arr1是一样的
        Integer[] arr2 = list.stream().toArray(Integer[]::new);
        System.out.println(Arrays.toString(arr2));
        //[1, 2, 3, 4, 5, 6]
        //[1, 2, 3, 4, 5, 6]
    }
}

小结

在这里插入图片描述
在这里插入图片描述

练习

在这里插入图片描述

  • testOne
public class testSeven {
    public static void main(String[] args) {
        ArrayList<String>list=new ArrayList<>();
        Collections.addAll(list,"张三,23","张即,23","张无,23","张四,23");
        Student[] arr1 = list.stream().
        map(Student::new).//这里使用构造方法的引用,
        //将Stream流中的数据装换成Student对象
        toArray(Student[]::new);//这里是引用数组的构造方法,创建了一个新数组
        System.out.println(Arrays.toString(arr1));
    }
}
  • testTwo
//我写的
public class testEight {
    public static void main(String[] args) {
        ArrayList<Student>list=new ArrayList<>();
        Collections.addAll(list,
                new Student("张三",23),
                new Student("张即",23),
                new Student("张无",23),
                new Student("张四",23));
        String[] arr = list.stream().map(testEight::getStr).toArray(String[]::new);
        System.out.println(Arrays.toString(arr));
    }
    public static String getStr(Student s){
        String name = s.getName();
        return name;
    }
}
//视频写的
public class testEight {
    public static void main(String[] args) {
        ArrayList<Student>list=new ArrayList<>();
        Collections.addAll(list,
                new Student("张三",23),
                new Student("张即",23),
                new Student("张无",23),
                new Student("张四",23));
        String[] arr = list.stream().
		//调用成员方法有两种方式
		//第一种:对象::成员方法
		//第一种要求形参和返回值完全一样
		//第二种:类名::成员方法
		//第二种要求返回值一样,抽象方法
		//形参第二个之后一样,如果没有第二个形参,就是空参函数
        map(Student::getName).
        //上面的getName就是空参函数,
        //public String getName() {
        //	return name;}				
        toArray(String[]::new);
        System.out.println(Arrays.toString(arr));
    }
}

方法引用技巧

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值