函数式接口:有且仅有一个抽象方法的接口
/*
定义一个类(RunnableDemo),在类中提供两个方法
一个方法是:startThread(Runnable r) 方法参数Runnable是一个函数式接口
一个方法是主方法,在主方法中调用startThread方法
*/
public class RunnableDemo {
public static void main(String[] args) {
//匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"启动了");
}
});
//Lambda表达式
startThread(()->System.out.println(Thread.currentThread().getName()+"启动了"));
}
private static void startThread(Runnable r){
//Thread t = new Thread(r,"stratThread");
//t.start();
new Thread(r,"stratThread").start();
}
}
运行结果:stratThread启动了
如果方法的参数是函数式接口,我们可以使用Lambda表达式作为参数传递
/*
定义一个类(ComparatorDemo),在类中提供两个方法
一个方法是:Comparator getComparator() 方法返回值Comparator是一个函数式接口
一个方法是主方法:在主方法中调用getComparator()方法
需求:比较字符串的长度,按照长短来排序
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class ComparatorDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("aaaa");
list.add("bbb");
list.add("sss");
list.add("c");
list.add("cddf");
System.out.println(list); //排序前
Collections.sort(list,getComparator());//第一个参数是集合对象,第二个参数是比较器
System.out.println(list); //排序后
}
//当函数式接口作为方法的返回值时,返回的是接口的实现类对象
private static Comparator<String> getComparator() {
//使用匿名内部类返回一个Comparator对象
/*Comparator c = new Comparator() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
return c;*/
/* return new Comparator() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};*/
//Lambda表达式
return (s1, s2) -> s1.length() - s2.length();
}
}
Supplier接口主要是用来生产数据的,包含一个无参的方法
import java.util.Arrays;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
Integer[] arr = {12,43,22,67,34,99};
//使用匿名内部类
/*Integer max = getMax(new Supplier() {
@Override
public Integer get() {
Arrays.sort(arr);
return arr[arr.length - 1];
}
});
*/
//Lambda表达式
Integer max = getMax(()->{
Arrays.sort(arr);
return arr[arr.length - 1];
});
System.out.println(max);
}
//使用Supplier接口作为参数,获取数组中的最大值
private static Integer getMax(Supplier<Integer> s){
return s.get();
}
}
运行结果: 99
Consumer:包含两个方法
- void accept(T t):对给定的参数执行此操作
- default Consumer andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
- Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
使用accept(T t)
public class ConsumerDemo {
public static void main(String[] args) {
String[] strings = {"路飞,19","索隆,22","山治,21","娜美,19"};
//使用匿名内部类
/*useString(strings, new Consumer() {
@Override
public void accept(String s) {
String[] split = s.split(",");
System.out.println("姓名;"+split[0]+",年龄:"+split[1]);
}
});*/
//Lambda表达式
useString(strings,s-> System.out.println("姓名;"+s.split(",")[0]+",年龄:"+s.split(",")[1]));
}
/**
* @param strarr
* @param con
*/
private static void useString(String[] strarr, Consumer<String> con){
//遍历数组获取元素,用于消费
for (String s : strarr) {
con.accept(s);//将String[] strarr集合中的元素依次取出,用于消费
}
}
}
运行结果:姓名;路飞,年龄:19
姓名;索隆,年龄:22
姓名;山治,年龄:21
姓名;娜美,年龄:19
使用Consumer andThen(Consumer after)
public class ConsumerDemo {
public static void main(String[] args) {
String[] strings = {"路飞,19","索隆,22","山治,21","娜美,19"};
//使用两个Consumer接口对象的方法
//匿名内部类
/* useString2(strings, new Consumer() {
@Override
public void accept(String s) {
System.out.print("姓名;"+s.split(",")[0]);
}
}, new Consumer() {
@Override
public void accept(String s) {
System.out.println(",年龄:"+s.split(",")[1]);
}
});
*/
//Lambda表达式
useString2(strings,
s ->System.out.print("姓名;"+s.split(",")[0]),
s -> System.out.println(",年龄:"+s.split(",")[1])
);
}
/**
* @param strarr
* @param con1
* @param con2
* 使用 andThen 方法将 Consumer 对象串联起来能够连续执行,消费同一个对象
*/
private static void useString2(String[] strarr,Consumer<String> con1,Consumer<String> con2){
for (String s : strarr) {
con1.andThen(con2).accept(s);//使用两个Consumer对象对同一个s进行操作
}
}
}
Predicate接口用于对参数进行判断是否满足指定条件
Predicate: 常用的四个方法
boolean
test(T t ): 对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值- default Predicate negate():返回一个逻辑的否定,对应逻辑非
- default Predicate and(Predicate other): 返回一个组合的判断,对应短路与
- default Predicate or(Predicate other): 返回一个组合的判断,对应短路或
① test、negate方法使用
public class Demo {
public static void main(String[] args) {
/* boolean result = usePredicate("hello", new Predicate() {
@Override
public boolean test(String s) {
return s.length()>8;
}
});*/
boolean b1 = usePredicate("hello", s -> s.length()>8);
System.out.println(b1);
boolean b2 = usePredicate("hellowrold", s -> s.length() < 15);
System.out.println(b2);
}
//
//判断字符串是否满足条件
private static boolean usePredicate(String str,Predicate<String> p){
// boolean test = p.test(str);
// return p.test(str);
return p.negate().test(str);
}
}
运行结果: true
false
② and(Predicate other)、or(Predicate other)方法使用
public class Demo2 {
public static void main(String[] args) {
boolean b = checkString("hello", s -> s .length() > 8, s -> s.length() < 15);
System.out.println(b);
}
//同一个字符串给出两个不同的判断条件,最后把这两个判断的结果做逻辑与运算和逻辑或运算
private static boolean checkString(String s, Predicate<String> p1, Predicate<String> p2) {
// boolean b1 = p1.test(s);
// boolean b2 = p2.test(s);
// return b1&&b2;
//使用and、or方法
// return p1.and(p2).test(s);
return p1.or(p2).test(s);
}
}
运行结果:true
练习
public class PredicateDemo1 {
public static void main(String[] args) {
String[] strArr = {"林青霞,30", "柳岩,43", "张曼玉,35", "貂蝉,28", "王祖贤,33"};
//调用usePredicate方法
//匿名内部类
/* usePredicate(strArr, new Predicate() {
@Override
public boolean test(String s) {//判断姓名长度是否大于3
return s.split(",")[0].length() > 3;
}
}, new Predicate() {
@Override
public boolean test(String s) {//判断年龄是否大于33
return Integer.parseInt(s.split(",")[1]) > 33;
}
});*/
//Lambda表达式
usePredicate(strArr,
s -> s.split(",")[0].length() > 2, //筛选姓名长度大于2的
s -> Integer.parseInt(s.split(",")[1]) > 33 //筛选年龄大于33的
);
}
private static void usePredicate(String[] strings, Predicate<String> pre1, Predicate<String> pre2) {
//用于将存放满足条件的数据
ArrayList<String> list = new ArrayList<>();
//遍历字符串数组
for (String string : strings) {
boolean test = pre1.and(pre2).test(string); //判断是否满足条件
if (test) {//如果test为true,那么将strings放入list中
list.add(string);
}
}
//遍历ArrayList
for (String s : list) {
System.out.println(s);
}
}
}
运行结果: 张曼玉,35
Function
public class Demo2 {
public static void main(String[] args) {
//定义一个方法,把一个字符串装换成int型,输出
// convert("100",s->Integer.parseInt(s));
//定义一个方法,把一个int型数据加上一个值后转成字符串,输出
// convert(12,integer -> String.valueOf(integer+21));
//定义一个方法,把一个字符串转换成int型,把int型的数据加上一个整数后,转为字符串输出
convert("12", s -> Integer.parseInt(s), i -> String.valueOf(i + 21));
}
//定义一个方法,把一个字符串转换成int型,把int型的数据加上一个整数后,转为字符串输出
private static void convert(String s, Function<String, Integer> f1, Function<Integer, String> f2) {
// Integer i = f1.apply(s);
// String ss = f2.apply(i);
// System.out.println(ss);
String apply = f1.andThen(f2).apply(s);
System.out.println(apply);
}
//定义一个方法,把一个int型数据加上一个值后转成字符串,输出
private static void convert(Integer i, Function<Integer, String> f) {
String result = f.apply(i);
System.out.println(result);
}
//定义一个方法,把一个字符串装换成int型,输出
private static void convert(String s, Function<String, Integer> f) {
Integer result = f.apply(s);
System.out.println(result);
}
}
Collection体系的集合可以使用默认方法stream()生成流
default Stream stream()
Map体系的集合间接地生成流
数组可以通过Stream接口的静态方法of(T…values)生成流
public class Demo2 {
public static void main(String[] args) {
//Collection体系可以使用默认方法stream()生成流
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<String>();
Stream<String> setStream = set.stream();
//Map体系的集合间接地生成流
Map<String,Integer> map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> vlaueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
//数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArray = {"hello","world","java"};
Stream<String> strArray1 = Stream.of(strArray);
Stream<String> strArray2 = Stream.of("hello", "world", "java");
}
}
Stream filter (Predicate predicate):用于对流中的数据进行过滤
Predicate 接口中的方法 Boolean test(T t):对给定的参数进行判断,返回一个布尔值
public class Demo1 {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("张三");
names.add("张曼玉");
names.add("张无忌");
names.add("林青霞");
names.add("张开泰");
names.add("王五");
//筛选除姓张的
ArrayList<String> zhangs = new ArrayList<>();
for (String name : names) {
if(name.startsWith("张")){
zhangs.add(name);
}
}
//在姓张的基础上筛选出姓名长度等于3的
ArrayList<String> three = new ArrayList<>();
for (String zhang : zhangs) {
if(zhang.length()==3){
three.add(zhang);
}
}
//输出最终结果
for (String s : three) {
System.out.println(s);
}
System.out.println("----------");
//使用stream流编程
names.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(System.out::println);
/**
* names.stream(): 生成stream流对象
* filter(s->s.startsWith("张")):过滤出以“张”开头的字符串
* filter(s->s.length()==3):在上一个条件的基础上,过滤出名字长度为三的字符串
* forEach(System.out::println):使用方法引用输出最终结果
*/
}
}
Stream limit(long n):返回截取的前 n 个元素组成的流
Stream skip(long n):跳过指定参数个数的元素,返回剩下元素组成的流
public class Demo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("宋七");
list.add("刘九");
//输出前4个元素
list.stream().limit(4).forEach(System.out::println);
System.out.println("----------");
//跳过前2个,输出剩余的
list.stream().skip(2).forEach(System.out::println);
System.out.println("----------");
//跳过前2个,输出剩余元素中的前2个
list.stream().skip(2).limit(2).forEach(System.out::println);
}
}
运行结果: 张三
李四
王五
赵六
----------
王五
赵六
宋七
刘九
----------
王五
赵六
Static Stream concat(Stream a, Stream b):合并a和b两个流为一个流
Stream distinct():返回该流的不同元素(根据 Object.equals(Object o))组成的流
public class Demo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
list.add("宋七");
list.add("刘九");
//需求1:取出前4个元素组成一个流
Stream<String> stream1 = list.stream().limit(4);
//需求2:跳过前2个,剩余的组成一个流
Stream<String> stream2 = list.stream().skip(2);
//需求3:将上面的两个流组合成一个流,并输出
// Stream.concat(stream1, stream2).forEach(System.out::println);
//需求4:合并需求1和需求2的流,并去除重复元素输出
Stream.concat(stream1, stream2).distinct().forEach(System.out::println);
}
}
Stream sorted(): 返回由此流的元素组成的流,自然排序
Stream sorted(Comparator comparator):返回由此流的元素组成的流,根据提供的Comparator进行排序
public class Demo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("aas");
list.add("acbds");
list.add("sccd");
list.add("cbffe");
list.add("scce");
//需求1:按照自然排序输出
// list.stream().sorted().forEach(System.out::println);
//需求2:按照字符串长度排序
// list.stream().sorted((s1, s2) -> s1.length()-s2.length()).forEach(System.out::println);
//需求3:按照长度排序,如果长度相同,那么再比较字母
list.stream().sorted((s1,s2)->{
int num = s1.length()-s2.length();
return num==0?s1.compareTo(s2):num;
}).forEach(System.out::println);
}
}
运行结果: aas
sccd
scce
acbds
cbffe
Stream map(Function m): 返回由给定函数应用于此流的元素的结果组成的流
IntStream mapToInt(ToIntFunction m): 返回一个IntStream 其中包含将给定函数应用于此流的元素的结果
IntStream接口
public class Demo6 {
public static void main(String[] args) {
//创建一个集合
ArrayList<String> list = new ArrayList<>();
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
list.add("7");
//需求1:将字符串转变成整数在控制台输出
// list.stream().map(s->Integer.parseInt(s)).forEach(System.out::println);
// list.stream().map(Integer::parseInt).forEach(System.out::println);
//int sum() 返回此流中元素的总和。
int sum = list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(sum);
//list.stream()生成一个stream流
//mapToInt(Integer::parseInt) 返回一个IntStream流
//sum()调用IntStream流的特有方法求和,返回一个整型
}
}
void forEach(Consumer action): 遍历元素并执行相应的操作
Consumer 接口中的方法 void accept(T t):对给定的参数执行操作
long count(): 返回此流中的元素个数
public class Demo7 {
public static void main(String[] args) {
ArrayList<String > list = new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("赵敏");
list.add("张天爱");
//需求1:把集合中的元素输出
// list.stream().forEach(System.out::println);
//需求2:统计集合中姓名以“张”开头的个数,并把统计结果在控制台输出
long count = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(count);
}
}
运行结果: 3
综合练习
/*
现有两个ArrayList集合,分别存储6名男演员名称和女演员名称,要求完成以下操作:
男演员只要名字为三个字的前三人
女演员只要姓林的并且不要第一个
把过滤后的男演员姓名和女演员姓名合并到一起
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带参构造,以及get、set方法
*/
import java.util.ArrayList;
import java.util.stream.Stream;
class Actor {
private String name;
public String getName() {
return name;
}
@Override
public String toString() {
return "Actor{" +
"name='" + name + '\'' +
'}';
}
public void setName(String name) {
this.name = name;
}
public Actor(String name) {
this.name = name;
}
}
public class Test_02 {
public static void main(String[] args) {
ArrayList<String> maleList = new ArrayList<>();
ArrayList<String> femaleList = new ArrayList<>();
maleList.add("周润发");
maleList.add("周星驰");
maleList.add("张国荣");
maleList.add("葛优");
maleList.add("吴京");
maleList.add("李连杰");
femaleList.add("王祖贤");
femaleList.add("林心如");
femaleList.add("林青霞");
femaleList.add("赵敏");
femaleList.add("巩俐");
femaleList.add("林黛玉");
//男演员只要名字为三个字的前三人
Stream<String> manStream = maleList.stream().filter(s -> s.length() == 3).limit(3);
//女演员只要姓林的并且不要第一个
Stream<String> womanStream = femaleList.stream().filter(s -> s.startsWith("林")).skip(1);
//把过滤后的男演员姓名和女演员姓名合并到一起
Stream<String> concatStream = Stream.concat(manStream, womanStream);
//把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
concatStream.map(s->new Actor(s)).forEach(System.out::println);
// concatStream.map(Actor::new).forEach(a-> System.out.println(a.getName()));
}
}
运行结果: Actor{name='周润发'}
Actor{name='周星驰'}
Actor{name='张国荣'}
Actor{name='林青霞'}
Actor{name='林黛玉'}
对数据使用Stream流的方式操作完毕后,我想把流中的数据收集到集合中,该怎么办?
stream流的收集方法
工具类Collectors 提供了具体的收集方法
public class Demo8 {
public static void main(String[] args) {
//创建List集合
List<String> list = new ArrayList<>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("赵敏");
//需求1:得到名字长度为3的流
Stream<String> lenStream = list.stream().filter(s -> s.length() == 3);
//需求2:把上一步得到的流中的数据收集到List集合中,并遍历
List<String> names = lenStream.collect(Collectors.toList());
names.forEach(System.out::println);
//创建Set集合
Set<Integer> set = new HashSet<>();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
//需求3:得到数字大于20的流
Stream<Integer> num = set.stream().filter(i -> i > 20);
//需求4:把上一步得到的流中的数据收集到Set集合中,并遍历
Set<Integer> numStream = num.collect(Collectors.toSet());
numStream.forEach(System.out::println);
//定义一个字符串数组,每一个元素由姓名和年龄组合而成
String[] strArray = {"魍魉,12","梅花十三,20","西凉,22","精卫,18"};
//需求5:得到字符串中年龄大于18的流
Stream<String> stringStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 18);
//需求6:把上一步中得到的流存储到Map集合中,其中名字做键,年龄做值
Map<String, String> student = stringStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> s.split(",")[1]));
//遍历集合
Set<Map.Entry<String, String>> entries = student.entrySet();
entries.forEach(s-> System.out.println("姓名:"+s.getKey()+",年龄:"+s.getValue()));
}
}
运行结果: 林青霞
张曼玉
王祖贤
40
30
姓名:西凉,年龄:22
姓名:梅花十三,年龄:20