[JAVA]函数式编程及Stream的操作
0.前言
Java 8时为了实现函数式编程,引出了三个重要概念
- Lambda 表达式,Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。但仅当接口只有一个抽象方法时,才可以使用 lambda 表达式。
- 方法引用,可以直接引用已有Java类或对象(实例)的方法或构造器。
- 函数式接口,一个有且仅有一个抽象方法,但可以有多个非抽象方法。函数式接口有@FunctionalInterface注解。
例如:
// 1. 无参无返回值
Runnable noArgsNoRet = () -> System.out.println("Hello Lambda");
// 2. 有参无返回值
Consumer<String> oneArgsNoRet = str -> System.out.println(str);
// 3. 无参有方法体
Supplier<String> noArgsHasRet = () -> {
String str = "a" + "b";
return str;
};
// 4. 有两个参数,有返回值,将方法体的计算结果作为返回值返回
BinaryOperator<Integer> add = (x, y) -> x + y;
// 5. 注明类型的参数
Consumer<String> oneArgs = (String str) -> System.out.println(str);
思想:Java 是面向对象的语言,变量只会被赋值为对象或基本类型,很显然函数不可能被赋值给变量!Java只是将函数这个行为,传递给了抽象接口的方法,告诉这个抽象接口,你的方法要用我的这个函数实现!
参考:https://zhuanlan.zhihu.com/p/407578877
1.四大函数式接口
1.1函数式接口说明
接口 | 方法 | 类型 | 说明 |
---|---|---|---|
Consumer | accept(Object) | 消费型 | 接受单个输入参数且不返回任何结果 |
Predicate | test(Object) | 断言型 | 接受单个输入参数且返回一个boolean |
Supplier | get() | 供给型 | 无参数,有返回值 |
Function | apply(Object) | 函数型 | 接受一个参数,有返回值 |
public static void main(String[] args) {
byte[] bytes = TestInterface.testFunction("abdsf", s -> s.getBytes());
boolean bool = TestInterface.testPredicate("adqwcfasfadf", s -> s.length() > 2);
String string = TestInterface.testSupplier(() -> "sad21da");
Integer[] ints = {1,5,2,8,2,3};
List<Integer> list = Arrays.asList(ints);
TestInterface.testCosumer(list, integers -> integers.forEach(integer -> System.out.print(integer)));
TestInterface.testCosumer(list, integers -> integers.forEach(System.out::print));
}
public static byte[] testFunction(String s, Function<String,byte[]> f){
return f.apply(s);
}
public static boolean testPredicate(String s, Predicate<String> p){
return p.test(s);
}
public static String testSupplier(Supplier<String> s){
return s.get();
}
public static void testCosumer(List<Integer> array, Consumer<List<Integer>> c){
c.accept(array);
}
2.函数式接口在Stream中的应用
2.1Stream的生成
/*
1.生成流的常用方式
*/
String[] strings = new String[]{"a","ab","a","cba"};
//1.1通过集合生成流
List<String> stringList = Arrays.asList(strings);
Stream<String> listStream = stringList.stream();
//1.2通过数组生成流
Stream<String> arraysStream = Arrays.stream(strings);
//1.3通过值
Stream<String> valueStream = Stream.of("a", "ab", "abc", "cba");
//1.4通过文件生成。通过Files.line方法得到流,每个流是文件中的一行
Stream<String> lineStream = Files.lines(Paths.get("config.properties"), Charset.defaultCharset());
2.2函数式接口及Stream的操作
Stream的操作:
一类是转换操作,即把一个Stream转换为另一个Stream,即方法调用后仍为一个Stream,例如map()和filter();
另一类是聚合操作,即对Stream的每个元素进行计算,得到一个确定的结果,可能是一个对象,也可能是返回空,例如reduce()。
2.2.1转换操作
/*
2. 流的中间操作
*/
//2.1 filter过滤,需要传Predicate类型的参数
Stream<String> filterStream = valueStream.filter((s) -> s.length() > 2);
//2.2 map
Stream<Integer> mapStream = valueStream.map(s -> s.length());
//2.3 sorted
Stream<String> sortedStream = valueStream.sorted(String::compareTo);
//2.4 distinct
Stream<String> distinctStream = valueStream.distinct();
//2.5 skip
Stream<String> skipStream = valueStream.skip(2);
//2.6 limit
Stream<String> limitStream = valueStream.skip(2).limit(1);
//2.7 concat
Stream<String> concatStream = Stream.concat(valueStream, limitStream);
//2.8 flatMap:flatMap的效果,各个数组不是分别映射成一个流,而是映射成流的内容
Stream<List<String>> valueStream1 = Stream.of(Arrays.asList("ac", "ad"), Arrays.asList("ac", "ad"));
Stream<String> stringStream = valueStream1.flatMap(list -> list.stream());
2.2.2转换操作
/*
3. 流的聚合操作
*/
//3.1 reduce
String reduceStream = valueStream.reduce("", (sall, s) -> sall + s);
List<String> reduce = valueStream.map(s -> {
List<String> asList = Arrays.asList(s.split(" "));
return asList;
}).reduce(new ArrayList<>(), (list, asList) -> {list.addAll(asList);return list;});
//3.2 foreach
valueStream.forEach(System.out::println);
//3.3 collect
List<String> collect = valueStream.collect(Collectors.toList());
//3.4 count
long count = valueStream.count();
//3.5 max
String s = valueStream.max((o1, o2) -> o1.compareTo(o2)).get();
参考:https://blog.csdn.net/qq_45797625/article/details/117636256