目录
一、不可变集合
1、创建不可变集合的应用场景
2、创建不可变集合的书写格式
2.1、不可变的List集合
2.2、不可变的Set集合
2.3、不可变的Map集合
3、小结
二、Stream流
1、体验Stream流的作用
2、Stream流的思想
3、Stream流的使用步骤
3.1、单列集合获取Stream流
3.2、双列集合获取Stream流(先转成keySet()或entrySet())
3.3、数组获取Stream流(Arrays.stream())
3.4、一堆零散数据(Stream.of())
4、Stream流的中间方法
三、方法引用
1、什么是方法引用?
1.1、示例代码
1.2、小结
2、方法引用的分类
2.1、引用静态方法(类名::静态方法)
2.2、引用成员方法(对象::成员方法)
2.3、引用构造方法(类名::new)
一、不可变集合
不可变集合:不可以被修改的集合
1、创建不可变集合的应用场景
2、创建不可变集合的书写格式
2.1、不可变的List集合
import java.util.Iterator;
import java.util.List;
public class ImmutableDemo1 {
public static void main(String[] args) {
/*
创建不可变的List集合
"张三", "李四", "王五", "赵六"
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
List<String> list = List.of("张三", "李四", "王五", "赵六");
System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(list.get(3));
System.out.println("---------------------------");
for (String s : list) {
System.out.println(s);
}
System.out.println("---------------------------");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("---------------------------");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
System.out.println("---------------------------");
//list.remove("李四");
//list.add("aaa");
list.set(0,"aaa");
}
}
2.2、不可变的Set集合
import java.util.Iterator;
import java.util.Set;
public class ImmutableDemo2 {
public static void main(String[] args) {
/*
创建不可变的Set集合
"张三", "李四", "王五", "赵六"
细节:
当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六");
for (String s : set) {
System.out.println(s);
}
System.out.println("-----------------------");
Iterator<String> it = set.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------------");
//set.remove("王五");
}
}
2.3、不可变的Map集合
10个参数以下使用Map.of()
import java.util.Map;
import java.util.Set;
public class ImmutableDemo3 {
public static void main(String[] args) {
/*
创建Map的不可变集合
细节1:
键是不能重复的
细节2:
Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
细节3:
如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Map<String, String> map = Map.of("张三", "南京", "张三", "北京", "王五", "上海",
"赵六", "广州", "孙七", "深圳", "周八", "杭州",
"吴九", "宁波", "郑十", "苏州", "刘一", "无锡",
"陈二", "嘉兴");
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + "=" + value);
}
System.out.println("--------------------------");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
System.out.println("--------------------------");
}
}
超过10个使用copyOf()
//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
import java.util.HashMap;
import java.util.Map;
public class ImmutableDemo4 {
public static void main(String[] args) {
/*
创建Map的不可变集合,键值对的数量超过10个
*/
//1.创建一个普通的Map集合
HashMap<String, String> hm = new HashMap<>();
hm.put("张三", "南京");
hm.put("李四", "北京");
hm.put("王五", "上海");
hm.put("赵六", "北京");
hm.put("孙七", "深圳");
hm.put("周八", "杭州");
hm.put("吴九", "宁波");
hm.put("郑十", "苏州");
hm.put("刘一", "无锡");
hm.put("陈二", "嘉兴");
hm.put("aaa", "111");
//2.利用上面的数据来获取一个不可变的集合
/*
//获取到所有的键值对对象(Entry对象)
Set<Map.Entry<String, String>> entries = hm.entrySet();
//把entries变成一个数组
Map.Entry[] arr1 = new Map.Entry[0];
//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
Map.Entry[] arr2 = entries.toArray(arr1);
//不可变的map集合
Map map = Map.ofEntries(arr2);
map.put("bbb","222");*/
//Map<Object, Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
Map<String, String> map = Map.copyOf(hm);
map.put("bbb","222");
}
}
3、小结
二、Stream流
Stream是Java 8 API添加的一个新的抽象,称为流Stream,以一种声明性方式处理数据集合(侧重对于源数据计算能力的封装,并且支持序列与并行两种操作方式)。流是个抽象的概念,是对输入输出设备的抽象,在Java程序中,对于数据的输入/输出操作都是以“流”的方式进行。
Stream流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算
Stream流是对集合(Collection)对象功能的增强,与Lambda表达式结合,可以提高编程效率、间接性和程序可读性。
1、体验Stream流的作用
普通代码:
//1.把所有以“张”开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for (String name : list1) {
if(name.startsWith("张")){
list2.add(name);
}
}
//2.把“张”开头的,长度为3的元素再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for (String name : list2) {
if(name.length() == 3){
list3.add(name);
}
}
//3.遍历打印最终结果
for (String name : list3) {
System.out.println(name);
}
Stream流:
/*
创建集合添加元素,完成以下需求:
1.把所有以“张”开头的元素存储到新集合中
2.把“张”开头的,长度为3的元素再存储到新集合中
3.遍历打印最终结果
*/
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("周芷若");
list1.add("赵敏");
list1.add("张强");
list1.add("张三丰");
list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
2、Stream流的思想
3、Stream流的使用步骤
示例代码:
3.1、单列集合获取Stream流
//1.单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
list.stream().forEach(s -> System.out.println(s));
该代码等于下面的一大堆
//获取到一条流水线,并把集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
//使用终结方法打印一下流水线上的所有数据
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
//s:依次表示流水线上的每一个数据
System.out.println(s);
}
});
3.2、双列集合获取Stream流(先转成keySet()或entrySet())
需要先获取KeySet()/entrySet()转换成单列集合才能使用
public class StreamDemo3 {
public static void main(String[] args) {
//双列集合 无 无法直接使用stream流
//1.创建双列集合
HashMap<String,Integer> hm = new HashMap<>();
//2.添加数据
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
//3.第一种获取stream流
//hm.keySet().stream().forEach(s -> System.out.println(s));
//4.第二种获取stream流
hm.entrySet().stream().forEach(s-> System.out.println(s));
}
}
3.3、数组获取Stream流(Arrays.stream())
//注意:
//Stream接口中静态方法of的细节
//方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
//但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
import java.util.stream.Stream;
public class StreamDemo4 {
public static void main(String[] args) {
// 数组 public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
//1.创建数组
int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
String[] arr2 = {"a","b","c"};
//2.获取stream流
// Arrays.stream(arr1).forEach(s-> System.out.println(s));
//System.out.println("============================");
//Arrays.stream(arr2).forEach(s-> System.out.println(s));
//System.out.println("============================");
//注意:
//Stream接口中静态方法of的细节
//方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
//但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
Stream.of(arr1).forEach(s-> System.out.println(s));//[I@41629346
}
}
3.4、一堆零散数据(Stream.of())
//一堆零散数据 public static<T> Stream<T> of(T... values) Stream接口中的静态方法
Stream.of(1,2,3,4,5).forEach(s-> System.out.println(s));
Stream.of("a","b","c","d","e").forEach(s-> System.out.println(s));
4、Stream流的中间方法
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
4.1、filter方法(过滤)
package com.yaqi.a01mystream;
import java.util.ArrayList;
import java.util.Collections;
public class StreamDemo6 {
public static void main(String[] args) {
/*
filter 过滤
limit 获取前几个元素
skip 跳过前几个元素
注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
//filter 过滤 把张开头的留下,其余数据过滤不要
/*list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
//如果返回值为true,表示当前数据留下
//如果返回值为false,表示当前数据舍弃不要
return s.startsWith("张");
}
}).forEach(s -> System.out.println(s));
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
System.out.println("====================================");
System.out.println(list);*/
/* limit 获取前几个元素
skip 跳过前几个元素*/
//"张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"
//list.stream().limit(3).forEach(s -> System.out.println(s));
//list.stream().skip(4) .forEach(s -> System.out.println(s));
//课堂练习:
//"张强", "张三丰", "张翠山"
//第一种思路:
//先获取前面6个元素:"张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山",
//然后跳过前面3个元素
//list.stream().limit(6).skip(3).forEach(s -> System.out.println(s));
//第二种思路:
//先跳过3个元素:"张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"
//然后再获取前面3个元素:"张强", "张三丰", "张翠山"
//list.stream().skip(3).limit(3).forEach(s -> System.out.println(s));
}
}
4.2、limit方法(获取前几个元素)
limit 获取前几个元素
skip 跳过前几个元素*/
//"张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"
//list.stream().limit(3).forEach(s -> System.out.println(s));
//list.stream().skip(4) .forEach(s -> System.out.println(s));
4.3、skip方法(跳过前几个元素)
list.stream().skip(4) .forEach(s -> System.out.println(s));
4.4 、练习
//课堂练习:
//"张强", "张三丰", "张翠山"
//第一种思路:
//先获取前面6个元素:"张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山",
//然后跳过前面3个元素
list.stream().limit(6).skip(3).forEach(s -> System.out.println(s));
//第二种思路:
//先跳过3个元素:"张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"
//然后再获取前面3个元素:"张强", "张三丰", "张翠山"
list.stream().skip(3).limit(3).forEach(s -> System.out.println(s));
4.5、distinct方法(元素去重)
自定义JavaBean需要中间去重写hashCode和equals方法
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张无忌","张无忌","张无忌", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "周芷若", "赵敏");
// distinct 元素去重,依赖(hashCode和equals方法)
list1.stream().distinct().forEach(s -> System.out.println(s));
4.6、concat方法(合并a和b两个流为一个流)
Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));
4.7、map方法(类型转换)
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20", "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");
//需求:只获取里面的年龄并进行打印
//String->int
//第一个类型:流中原本的数据类型
//第二个类型:要转成之后的类型
//apply的形参s:依次表示流里面的每一个数据
//返回值:表示转换之后的数据
//当map方法执行完毕之后,流上的数据就变成了整数
//所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");
String ageString = arr[1];
int age = Integer.parseInt(ageString);
return age;
}
}).forEach(s-> System.out.println(s));
System.out.println("------------------------");
list.stream()
.map(s-> Integer.parseInt(s.split("-")[1]))
.forEach(s-> System.out.println(s));
5、Stream流的终结方法
5.1、forEach方法(遍历)
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
//void forEach(Consumer action) 遍历
//Consumer的泛型:表示流中数据的类型
//accept方法的形参s:依次表示流里面的每一个数据
//方法体:对每一个数据的处理操作(打印)
/*list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
list.stream().forEach(s -> System.out.println(s));
5.2、count方法(统计)
// long count() 统计
long count = list.stream().count();
System.out.println(count);
5.3、toArray方法(收集流中的数据,放到数组中)
// toArray() 收集流中的数据,放到数组中
//Object[] arr1 = list.stream().toArray();
//System.out.println(Arrays.toString(arr1));
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组
//方法体:就是创建数组
//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
/* String[] arr = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));*/
String[] arr2 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(arr2));
5.4、collect方法(收集流中的数据,放到集合中)
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamDemo10 {
public static void main(String[] args) {
/*
collect(Collector collector) 收集流中的数据,放到集合中 (List Set Map)
注意点:
如果我们要收集到Map集合当中,键不能重复,否则会报错
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
"张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");
//收集List集合当中
//需求:
//我要把所有的男性收集起来
List<String> newList1 = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toList());
//System.out.println(newList1);
//收集Set集合当中
//需求:
//我要把所有的男性收集起来
Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
//System.out.println(newList2);
//收集Map集合当中
//谁作为键,谁作为值.
//我要把所有的男性收集起来
//键:姓名。 值:年龄
Map<String, Integer> map = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
/*
* toMap : 参数一表示键的生成规则
* 参数二表示值的生成规则
*
* 参数一:
* Function泛型一:表示流中每一个数据的类型
* 泛型二:表示Map集合中键的数据类型
*
* 方法apply形参:依次表示流里面的每一个数据
* 方法体:生成键的代码
* 返回值:已经生成的键
*
*
* 参数二:
* Function泛型一:表示流中每一个数据的类型
* 泛型二:表示Map集合中值的数据类型
*
* 方法apply形参:依次表示流里面的每一个数据
* 方法体:生成值的代码
* 返回值:已经生成的值
*
* */
.collect(Collectors.toMap(new Function<String, String>() {
@Override
public String apply(String s) {
//张无忌-男-15
return s.split("-")[0];
}
},
new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[2]);
}
}));
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);
}
6、小结
三、方法引用
1、什么是方法引用?
方法引用就是把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体
函数式接口:FunctionInterface
1.1、示例代码
匿名内部类:
import java.util.Arrays;
public class FunctionDemo1 {
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;
}
});*/
//lambda表达式
//因为第二个参数的类型Comparator是一个函数式接口
/* Arrays.sort(arr, (Integer o1, Integer o2)->{
return o2 - o1;
});*/
//lambda表达式简化格式
//Arrays.sort(arr, (o1, o2)->o2 - o1 );
//方法引用
//1.引用处需要是函数式接口
//2.被引用的方法需要已经存在
//3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//4.被引用方法的功能需要满足当前的要求
//表示引用FunctionDemo1类里面的subtraction方法
//把这个方法当做抽象方法的方法体
Arrays.sort(arr, FunctionDemo1::subtraction);
System.out.println(Arrays.toString(arr));
}
//可以是Java已经写好的,也可以是一些第三方的工具类
public static int subtraction(int num1, int num2) {
return num2 - num1;
}
}
1.2、小结
2、方法引用的分类
2.1、引用静态方法(类名::静态方法)
package com.yaqi.a01myfunction;
import java.util.ArrayList;
import java.util.Collections;
public class FunctionDemo2 {
public static void main(String[] args) {
/*
方法引用(引用静态方法)
格式
类::方法名
需求:
集合中有以下数字,要求把他们都变成int类型
"1","2","3","4","5"
*/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"1","2","3","4","5");
//2.把他们都变成int类型
/* list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s);
return i;
}
}).forEach(s -> System.out.println(s));*/
//1.方法需要已经存在
//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//3.方法的功能需要把形参的字符串转换成整数
list.stream()
.map(Integer::parseInt)
.forEach(s-> System.out.println(s));
}
}
2.2、引用成员方法(对象::成员方法)
方法引用(引用成员方法)
格式
其他类:其他类对象::方法名
本类:this::方法名(引用处不能是静态方法)
父类:super::方法名(引用处不能是静态方法)
需求: 集合中有一些名字,按照要求过滤数据 数据:"张无忌","周芷若","赵敏","张强","张三丰" 要求:只要以张开头,而且名字是3个字的
//1.创建集合
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//3.过滤数据(只要以张开头,而且名字是3个字的)
//list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(s-> System.out.println(s));
/* list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length() == 3;
}
}).forEach(s-> System.out.println(s));*/
/* StringOperation so = new StringOperation();
list.stream().filter(so::stringJudge)
.forEach(s-> System.out.println(s));*/
//静态方法中是没有this的
list.stream().filter(new FunctionDemo3()::stringJudge)
.forEach(s-> System.out.println(s));
}
public boolean stringJudge(String s){
return s.startsWith("张") && s.length() == 3;
}
App
package com.yaqi.a02game;
public class App {
public static void main(String[] args) {
new LoginJFrame();
}
}
MyJFrame
package com.yaqi.a02game;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class MyJFrame extends JFrame {
public void method1(ActionEvent e) {
System.out.println("go按钮被点击了");
}
}
LoginJFrame
package com.yaqi.a02game;
import javax.swing.*;
import java.awt.*;
public class LoginJFrame extends MyJFrame {
JButton go = new JButton("Go");
public LoginJFrame() {
//设置图标
setIconImage(Toolkit.getDefaultToolkit().getImage("myfunction\\image\\logo.jpg"));
//设置界面
initJframe();
//添加组件
initView();
//界面显示出来
this.setVisible(true);
}
//添加组件
public void initView() {
JLabel image = new JLabel(new ImageIcon("myfunction\\image\\kit.jpg"));
image.setBounds(100,50,174,174);
this.getContentPane().add(image);
go.setFont(new Font(null,1,20));
go.setBounds(120,274,150,50);
go.setBackground(Color.WHITE);
go.addActionListener(super::method1);
this.getContentPane().add(go);
}
//设置界面
public void initJframe() {
//设置标题
this.setTitle("随机点名器");
//设置大小
this.setSize(400, 500);
//设置关闭模式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口无法进行调节
this.setResizable(false);
//界面居中
this.setLocationRelativeTo(null);
//取消内部默认居中放置
this.setLayout(null);
//设置背景颜色
this.getContentPane().setBackground(Color.white);
this.setAlwaysOnTop(true);//置顶
}
}
本类:this::方法名(引用处不能是静态方法)
父类:super::方法名(引用处不能是静态方法)
2.3、引用构造方法(类名::new)
package com.yaqi.a01myfunction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class FunctionDemo4 {
public static void main(String[] args) {
/*
方法引用(引用构造方法)
格式
类名::new
目的:
创建这个类的对象
需求:
集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致
4.被引用方法的功能需要满足当前的需求
*/
//1.创建集合对象
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");
//3.封装成Student对象并收集到List集合中
//String --> Student
/* List<Student> newList = list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
String[] arr = s.split(",");
String name = arr[0];
int age = Integer.parseInt(arr[1]);
return new Student(name, age);
}
}).collect(Collectors.toList());
System.out.println(newList);*/
List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(newList2);
}
}
只需要保证构造方法结束后生成的对象与抽象方法的返回值保持一致就可以了
2.4、其它调用方式(Ⅰ. 使用类名引用成员方法 Ⅱ. 引用数组的构造方法)
2.4.1 使用类名引用成员方法
package com.yaqi.a01myfunction;
import java.util.ArrayList;
import java.util.Collections;
public class FunctionDemo5 {
public static void main(String[] args) {
/*
方法引用(类名引用成员方法)
格式
类名::成员方法
需求:
集合里面一些字符串,要求变成大写后进行输出
*/
//1.创建集合对象
ArrayList<String> list = new ArrayList<>();
//2.添加数据
Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");
//3.变成大写后进行输出
//map(String::toUpperCase)
//拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换之后的结果。
list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
//String --> String
/* list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s -> System.out.println(s));*/
}
}
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
4.被引用方法的功能需要满足当前的需求
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在Stream流当中,第一个参数一般都表示流里面的每一个数据。
假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
参数类型必须相同
2.4.2引用数组的构造方法
细节: 数组的类型,需要跟流中数据的类型保持一致。
package com.yaqi.a01myfunction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class FunctionDemo6 {
public static void main(String[] args) {
/*
方法引用(数组的构造方法)
格式
数据类型[]::new
目的:
创建一个指定类型的数组
需求:
集合中存储一些整数,收集到数组当中
细节:
数组的类型,需要跟流中数据的类型保持一致。
*/
//1.创建集合并添加元素
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
//2.收集到数组当中
Integer[] arr2 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr2));
/*Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});*/
//3.打印
}
}
3、小结
4、方法引用综合小练习
①、练习1
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class FunctionDemo7 {
public static void main(String[] args) {
/*
需求:
集合中存储一些字符串的数据,比如:张三,23。
收集到Student类型的数组当中
*/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");
//2.先把字符串变成Student对象,然后再把Student对象收集起来
Student[] arr = list.stream().map(Student::new).toArray(Student[]::new);
//打印数组
System.out.println(Arrays.toString(arr));
}
}
②、练习 2
技巧: * 1.现在有没有一个方法符合我当前的需求 * 2.如果有这样的方法,这个方法是否满足引用的规则 * 静态 类名::方法名 * 成员方法 * 构造方法 类名::new
//1.创建集合
ArrayList<Student> list = new ArrayList<>();
//2.添加元素
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
list.add(new Student("wangwu",25));
//3.获取姓名并放到数组当中
String[] arr = list.stream().map(Student::getName).toArray(String[]::new);
/* String[] arr = list.stream().map(new Function<Student, String>() {
@Override
public String apply(Student student) {
return student.getName();
}
}).toArray(String[]::new);*/
System.out.println(Arrays.toString(arr));
③、练习3
相当于练习1和练习2的结合:(在Student.java中新增了一个方法getNameAge,用以返回对应格式的字符串)
public String getNameAge(){
return name+'-'+age;
}
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
list.add(new Student("wangwu",25));
String[] array = list.stream().map(Student::getNameAge).toArray(String[]::new);
System.out.println(Arrays.toString(array));