目录
不可变集合详解(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));
}
}