Java笔记之 函数式接口、Stream流
函数式接口
函数式接口概述
函数式接口:有且仅有一个抽象方法的接口
Java的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口,只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利的进行推导。
如何检测一个接口是不是函数式接口呢?
@FunctionalInterface,放在接口定义的上方:如果接口是函数式接口,那么编译通过,如果不是,编译失败
自己定义的时候,加不加上这个注解都可以,但是建议加上。
函数式接口作为方法的参数
需求:
定义一个RunnableDemo类,在类中提供两个方法
1.startThread(Runnable r),方法参数Runnable是一个函数式接口。
2.主方法,在主方法中调用startThread方法。
如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递
startThread(()->System.out.println(Thread.currentThread().getName()+"线程启动了"));
-
package com.FunctionInterface;
-
-
public class RunnableDemo {
-
public static void main(String[] args) {
-
startThread(new Runnable() {
-
@Override
-
public void run() {
-
System.out.println(Thread.currentThread().getName()+"线程启动了");
-
}
-
});
-
}
-
startThread(()->System.out.println(Thread.currentThread().getName()+"线程启动了"));
-
-
private static void startThread(Runnable r) {
-
// Thread t = new Thread(r);
-
// t.start();
-
new Thread(r).start();
-
}
-
}
函数式接口作为方法的返回值
需求:
定义一个ComparatorDemo类,在类中提供两个方法
1.Comparator<String> getComparator(),方法返回值Comparator是一个函数式接口。
2.主方法,在主方法中调用getComparator()方法。
如果方法返回是一个函数式接口,我们可以使用Lambda表达式作为结果返回
private static Comparator<String> getComparator(){
return (s1,s2)->s1.length()-s2.length();
}
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
import java.util.Collections;
-
import java.util.Comparator;
-
-
public class ComparatorDemo {
-
public static void main(String[] args) {
-
ArrayList<String> s = new ArrayList<>();
-
s.add("sss");
-
s.add("derde");
-
s.add("asedeff");
-
s.add("w");
-
System.out.println(s);
-
Collections.sort(s);
-
System.out.println(s);
-
Collections.sort(s,getComparator());
-
System.out.println(s);
-
-
}
-
private static Comparator<String> getComparator(){
-
//匿名内部类的实现
-
// Comparator<String> comp = new Comparator<String>() {
-
// @Override
-
// public int compare(String s1, String s2) {
-
// return s1.length()-s2.length();
-
// }
-
// };
-
// return comp;
-
-
// return new Comparator<String>() {
-
// @Override
-
// public int compare(String s1, String s2) {
-
// return s1.length()-s2.length();
-
// }
-
// };
-
-
// return (String s1,String s2)->{
-
// return s1.length()-s2.length();
-
// };
-
-
return (s1,s2)->s1.length()-s2.length();
-
}
-
-
}
常用的函数式接口
1.Supplier接口
2.Consumer接口
3.Predicate接口
4.Function接口
Supplier接口
Supplier<T> :包含一个无参的方法
该方法不需要参数,他会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。
Supplier<T> 接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
-
package com.FunctionInterface;
-
-
import java.util.function.Supplier;
-
-
public class SupplierDemo {
-
public static void main(String[] args) {
-
String s = getString(new Supplier<String>() {
-
@Override
-
public String get() {
-
return "zayn";
-
}
-
});
-
System.out.println(s);
-
String ss = getString(()-> "zayn");
-
System.out.println(ss);
-
int x = getInteger(()->22);
-
System.out.println(x);
-
}
-
private static String getString(Supplier<String> sup){
-
return sup.get();
-
}
-
public static Integer getInteger(Supplier<Integer> sup){
-
return sup.get();
-
}
-
-
}
Consumer接口
Consumer<T>包含两个方法
1.void accept(T t):对给定的参数执行此操作
2.default Consumer<T> andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
Consumer<T>接口也被称为消费型接口,他消费的数据的数据类型由泛型指定
-
package com.FunctionInterface;
-
-
import java.util.function.Consumer;
-
-
public class ConsumerDemo {
-
public static void main(String[] args) {
-
operateString("hh", new Consumer() {
-
@Override
-
public void accept(Object s) {
-
System.out.println(s);
-
}
-
});
-
operateString("zayn",(s)-> System.out.println(s));
-
operateString("naill",System.out::println);
-
operateString("zayn",(s)-> System.out.println(s),(s)-> System.out.println(new StringBuilder(String.valueOf(s)).reverse().toString()));
-
}
-
private static void operateString(String s,Consumer con){
-
con.accept(s);
-
}
-
private static void operateString(String s,Consumer con1,Consumer con2){
-
con1.andThen(con2).accept(s);
-
-
}
-
}
Predicate接口
Predicate<T>:常用的四个方法
1.boolean test(T t):对于给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
2.default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非
3.default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与
4.default Predicate<T> or (Predicate other):返回一个组合判断,对应短路或
Predicate<T> 接口通常用于判断参数是否满足指定条件
-
package com.FunctionInterface;
-
-
import java.util.function.Predicate;
-
-
public class PredicateDemo {
-
public static void main(String[] args) {
-
//boolean b = checkString("zayn",s-> s.length()>5);
-
boolean b = checkString("zayn",(String s)->{
-
return s.length()>5;
-
});
-
System.out.println(b);
-
boolean bb = checkString("zayn",s->s.length()>5,s -> s.length()<10);
-
System.out.println(bb);
-
-
}
-
private static boolean checkString(String s, Predicate<String> p){
-
//return p.test(s);
-
//return !p.test(s);
-
return p.negate().test(s);
-
}
-
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;
-
//return p1.and(p2).test(s);
-
return p1.or(p2).test(s);
-
}
-
}
Function接口
Function<T,R>:常用的两个方法
1. R apply(T t):将此函数应用于给定的参数
2.default<V> Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
Function<T,R>接口通常用于对参数进行处理、转换(处理逻辑由Lambda表达式实现),然后返回一个新的值
-
package com.FunctionInterface;
-
-
import java.util.function.Function;
-
-
public class FunctionDemo {
-
public static void main(String[] args) {
-
convert("100",s->Integer.parseInt(s));
-
convert("100",Integer::parseInt);
-
convert(100,i->String.valueOf(i+566));
-
convert("100",s->Integer.parseInt(s),i->String.valueOf(i+566));
-
}
-
//定义一个方法,把一个字符串转换为int类型,在控制台上输出
-
private static void convert(String s, Function<String,Integer> fun){
-
int i = fun.apply(s);
-
System.out.println(i);
-
}
-
//定义一个方法,把一个int类型的数据加上一个整数后,转换为字符串进行输出
-
private static void convert(int i ,Function<Integer,String> fun){
-
String s = fun.apply(i);
-
System.out.println(s);
-
}
-
//定义一个方法,把一个字符串转换为int类型,把一个int类型的数据加上一个整数后,转换为字符串进行输出
-
private static void convert(String s,Function<String,Integer> fun1,Function<Integer,String> fun2){
-
// String ss = fun2.apply(fun1.apply(s));
-
// System.out.println(ss);
-
String ss = fun1.andThen(fun2).apply(s);
-
System.out.println(ss);
-
}
-
-
}
Stream流
体验Stream流
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
-
public class StreamDemo {
-
public static void main(String[] args) {
-
ArrayList<String> list = new ArrayList<>();
-
list.add("林青霞");
-
list.add("张曼玉");
-
list.add("王祖贤");
-
list.add("柳岩");
-
list.add("张三");
-
list.add("张无忌");
-
list.stream().filter(s->s.length()==3).filter(s -> s.startsWith("张")).forEach(System.out::println);
-
}
-
}
Stream流的生成方式
stream流的常见生成方式
1.Collection体系的集合可以使用默认方法stream()生成流 default Stream<E> stream()
2.Map体系的集合间接的生成流
3.数组可以通过Stream接口的静态方法of(T...values)生成流
-
package com.FunctionInterface;
-
-
import java.util.*;
-
import java.util.stream.Stream;
-
-
public class StreamDemo1 {
-
public static void main(String[] args) {
-
-
//Collection体系的集合可以使用默认方法stream()生成流 default Stream<E> stream()
-
List<String> l = new ArrayList<>();
-
Stream<String> listStream = l.stream();
-
Set<String> s = new HashSet<>();
-
Stream<String> setStream = s.stream();
-
-
//Map体系的集合间接的生成流
-
Map<String,Integer> map = new HashMap<>();
-
Stream<String> keyStream = map.keySet().stream();
-
Stream<Integer> valueStream = map.values().stream();
-
Stream<Map.Entry<String,Integer>> entryStream = map.entrySet().stream();
-
-
//数组可以通过Stream接口的静态方法of(T...values)生成流
-
String[] strArray = {"hello","java","zayn"};
-
Stream<String> strArrayStream1 = Stream.of(strArray);
-
Stream<String> strArrayStream2 = Stream.of("hello","java","zayn");
-
Stream<Integer>intStream = Stream.of(1,2,3,4,5);
-
}
-
}
Stream流中常见的中间操作方法
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
import java.util.stream.Stream;
-
-
public class StreamDemo2 {
-
public static void main(String[] args) {
-
ArrayList<String> list = new ArrayList<>();
-
list.add("林青霞");
-
list.add("张曼玉");
-
list.add("王祖贤");
-
list.add("柳岩");
-
list.add("张敏");
-
list.add("张无忌");
-
-
//需求1:取前3个数据在控制台输出
-
list.stream().limit(3).forEach(System.out::println);
-
System.out.println("--------");
-
//需求2:跳过前三个数据,剩余的数据在控制台输出
-
list.stream().skip(3).forEach(System.out::println);
-
System.out.println("--------");
-
//需求3:跳过前2个数据,取前2个数据在控制台输出
-
list.stream().skip(2).limit(2).forEach(System.out::println);
-
System.out.println("--------");
-
//需求4:取前4个数据组成一个流
-
Stream<String> s1 = list.stream().limit(4);
-
System.out.println("--------");
-
//需求5:跳过2个数据组成一个流
-
Stream<String> s2 = list.stream().skip(2);
-
System.out.println("--------");
-
//需求6:合并需求4和需求5得到一个流,并把结果在控制台上输出
-
//Stream.concat(s1,s2).forEach(System.out::println);
-
System.out.println("--------");
-
//需求7:合并需求4和需求5得到一个流,并把结果在控制台上输出,要求字符串元素不能重复
-
Stream.concat(s1,s2).distinct().forEach(System.out::println);
-
System.out.println("--------");
-
System.out.println("deretfrefewrfgerg");
-
}
-
}
-
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
-
public class StreamDemo3 {
-
public static void main(String[] args) {
-
ArrayList<String> list = new ArrayList<>();
-
list.add("defrefrg");
-
list.add("deffffff");
-
list.add("cdfref");
-
list.add("aaa");
-
list.add("wwwwwwww");
-
list.add("defferrf");
-
-
//需求1:按照字母顺序把数据在控制台输出
-
list.stream().sorted().forEach(System.out::println);
-
System.out.println("--------");
-
//需求2:按照字符串长度把数据在控制台输出
-
//list.stream().sorted((s1,s2)->s1.length()-s2.length()).forEach(System.out::println);
-
list.stream().sorted((s1,s2)->{
-
int l = s1.length()-s2.length();
-
int num = l==0?s1.compareTo(s2):l;
-
return num;
-
}).forEach(System.out::println);
-
//需求1:按照字母顺序把数据在控制台输出
-
}
-
}
-
-
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
-
public class StreamDemo4 {
-
public static void main(String[] args) {
-
ArrayList<String> list = new ArrayList<>();
-
list.add("10");
-
list.add("20");
-
list.add("30");
-
list.add("40");
-
list.add("50");
-
-
//需求:将集合中的数据转换成整数后在控制台输出
-
//list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
-
list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
-
-
//int sum() 返回此流中元素对总和
-
int result = list.stream().mapToInt(Integer::parseInt).sum();
-
System.out.println(result);
-
}
-
}
-
Stream流中常见的终结方法
1.void forEach(Consumer action):对流的每个元素执行操作,Consumer接口中的方法 void accept(T t):对给定的参数执行此操作
2.long count():返回此流的元素数
-
package com.FunctionInterface;
-
-
import java.util.ArrayList;
-
-
public class StreamDemo {
-
public static void main(String[] args) {
-
ArrayList<String> list = new ArrayList<>();
-
list.add("林青霞");
-
list.add("张曼玉");
-
list.add("王祖贤");
-
list.add("柳岩");
-
list.add("张三");
-
list.add("张无忌");
-
//list.stream().filter(s->s.length()==3).filter(s -> s.startsWith("张")).forEach(System.out::println);
-
list.stream().forEach(System.out::println);
-
System.out.println(list.stream().filter(s -> s.startsWith("张")).count());
-
}
-
}
Stream流的收集操作
对数据使用Stream流的方式操作完毕后,我想把流中的数据收集到集合中,怎么办?
Stream流的收集方法
1.R collect(Collector collector)
2.但是这个收集方法的参数是一个collection的接口
工具类Collectors提供了具体的收集方式
1.public static <T> Collector toList():把元素收集到list集合中
2.public static <T> Collector toSet():把元素收集到set集合中
3.public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到map集合中
-
package com.FunctionInterface;
-
import java.util.*;
-
import java.util.stream.Collector;
-
import java.util.stream.Collectors;
-
import java.util.stream.Stream;
-
-
-
public class CollectionDemo1 {
-
public static void main(String[] args) {
-
List<String> list = new ArrayList<>();
-
list.add("林青霞");
-
list.add("张曼玉");
-
list.add("王祖贤");
-
list.add("柳岩");
-
-
//需求1.得到名字为3个字的流
-
Stream<String> stream = list.stream().filter(s->s.length()==3);
-
-
//需求2.把stream流操作完毕的数据收集到List集合中并遍历
-
//List<String> names = stream.collect(Collectors.toList());
-
Set<String> names = stream.collect(Collectors.toSet());
-
for(String name:names){
-
System.out.println(name);
-
}
-
-
//创建set集合
-
Set<Integer> set = new HashSet<>();
-
set.add(10);
-
set.add(20);
-
set.add(30);
-
set.add(40);
-
set.add(50);
-
-
//需求3.得到年龄大于25的流
-
Stream<Integer> stream1 = set.stream().filter(i->i>25);
-
-
//需求4.把stream流操作完毕的数据收集到Set集合中并遍历
-
Set<Integer> s = stream1.collect(Collectors.toSet());
-
for(int i : s){
-
System.out.println(i);
-
}
-
-
//定义一个字符串数组,每一个字符串的数据由姓名和年龄组成
-
String[] strArray = { "林青霞,30","张曼玉,35","王祖贤,33","柳岩,25"};
-
-
//需求5.得到字符串中年龄大于28的流
-
Stream<String> stream2 = Stream.of(strArray).filter( ss ->Integer.parseInt(ss.split(",")[1])>28);
-
-
//需求6.把stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名做键,年龄做值
-
Map<String,Integer> map = stream2.collect(Collectors.toMap(s1->s1.split(",")[0],s2->Integer.parseInt(s2.split(",")[1])));
-
Set<String> keySet = map.keySet();
-
for(String key :keySet){
-
System.out.println(key+":"+map.get(key));
-
}
-
}
-
}