一、函数式接口
接口中只有一个抽象方法时,该接口就是函数式接口
.为什么叫做函数式接口?因为这种接口,放在方法中当参数时,可以改造成lambda,进行运算.
Java提供了一个注解可以校验接口是否是函数式接口
@FunctionalInterface
Java中提供了几个特别常用的函数式接口
Supplier 供应,即返回一个数据 (无参有返回值的方法)
Consumer 消费,即给其传入数据做运算 (有参无返回值的方法)
Function 函数,传入2个参数,用于转换数据的 (有参有返回值的方法)
Predicate 判断,返回时boolean (有参,返回值是boolean)
为什么设计这些接口? 因为之前演示lambda时,需要自己设计一些IA , IB等接口,现在可以直接使用这些接口
1、 Supplier
JDK中Supplier.java源码
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda
练习,设计方法,通过Supplier接口,获得字符串的长度
public static void main(String[] args) {
get(() -> {
int length = "asdafasfasdf".length( );
return length;
});
}
// 设计方法,方法的参数是Supplier
// 需求1:获得字符串的长度
public static void get(Supplier<Integer> supplier) {
Integer i = supplier.get( );
System.out.println(i );
}
2、 Consumer
JDK中Consumer.java源码
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
* 给传入一个值,对该值进行操作
* @param t the input argument
*/
void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda
3、 Function
JDK中Function.java源码
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda
练习,设计方法,将传入的字符串数字,转为整形数字
// 设计方法,将传入的字符串数字,转为整形数字
public static void to(Function<String,Integer> function) {
Integer i = function.apply("1111");
System.out.println(i + 2);
}
public static void main(String[] args) {
to(t -> Integer.parseInt(t));
}
4、 Predicate
JDK中Predicate.java源码
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
判断数据是否是偶数
// 设计方法,判断数据是否是偶数
public static void pd(Predicate<Integer> predicate) {
boolean test = predicate.test(1);
System.out.println(test );
}
public static void main(String[] args) {
pd(i -> i % 2 == 0);
}
5、 总结
这些函数式认识即可,一般是用在下面Stream流中的
现在学习这几个函数式接口,就是让大家知道这些接口特性:
比如有无参数,参数类型和个数
比如有无返回值,返回值类型
以及用法,就是这些接口一般都会用在哪种场景下?
Supplier接口的方法一般用于
获得数据
Consumer接口的方法 一般用于
处理数据
Function接口的方法一般用于
转换数据
Predicate接口的方法一般用于
判断数据
二、Stream流[重点]
Stream流,不要和之前学的IO流进行联想,他们之间没有关系.
IO流,数据像水流一样在传输,即IO流强调是
传输数据
Stream流,数据像车间流水线,在一直往下走动,不是保存数据,也不纯粹的传输数据,而是像车间流水线一样,在
处理数据
.
1、 获得流
Java提供了几种方式,可以让我们获得Stream流
[集合创建流]Collection 接口的 stream()或 parallelStream()方法
[自由值创建]静态的 Stream.of(...)、Stream.empty()方法
[数组创建流]Arrays.stream(array)
静态的 Stream.generate()方法生成无限流,接受一个不包含引元的函数
静态的 Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
Pattern 接口的 splitAsStream(input)方法
静态的 Files.lines(path)、Files.lines(path, charSet)方法
静态的 Stream.concat()方法将两个流连接起来
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>( );
list.add(1);
list.add(2);
list.add(3);
list.add(4);
// 方式1: 从集合获得流
Stream<Integer> stream = list.stream( );
int[] arr = {1,2,3,4,5};
// 方式2: 从数组获得流
IntStream stream2 = Arrays.stream(arr);
// 方式3: 直接创建流
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
}
2、 Stream操作[重点]
Stream流就是流式处理数据,流的操作有很多种
中间操作(真正处理数据的操作)
中间操作就是执行完返回的是一个流,即可以
继续执行
流操作敲代码来说,就是使用中间操作的方法,写完继续再.调用其他方法
终止操作(将
操作完的结果返回
)
敲代码来说,调用终止方法,代码就结束;
操作 | 函数 | 说明 |
---|---|---|
中间操作 | filter(Predicate) | 将结果为false的元素过滤掉 |
中间操作 | map(Function) | 转换元素的值,可以用方法引元或者lambda表达式 |
中间操作 | flatMap(Function) | 若元素是流,将流摊平为正常元素,再进行元素转换(合并两个流为一个流) |
中间操作 | limit(long n) | 保留前n个元素 |
中间操作 | skip(long n) | 跳过前n个元素 |
中间操作 | concat(Stream s1, Stream s2) | 将两个流拼接起来 |
中间操作 | distinct() | 剔除重复元素 |
中间操作 | sorted() | 将Comparable元素的流排序 |
中间操作 | sorted(Comparator) | 将流元素按Comparator排序 |
中间操作 | peek(Consumer) | 流不变,但会把每个元素传入fun执行,可以用作调试 |
终结操作 | max(Comparator) | 取最大值 |
终结操作 | min(Comparator) | 取最小值 |
终结操作 | count() | 统计元素数量 |
终结操作 | findFirst() | 获得流的第一个元素 |
终结操作 | findAny() | 返回任意元素 |
终结操作 | anyMatch(Predicate) | 任意元素匹配时返回true |
终结操作 | allMatch(Predicate) | 所有元素匹配时返回true |
终结操作 | noneMatch(Predicate) | 没有元素匹配时返回true |
终结操作 | reduce(Function) | 从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数 |
终结操作 | iterator() | 迭代器迭代元素 |
终结操作 | forEach(Consumer) | lambda的方式迭代 |
终结操作 | forEachOrdered(Consumer) | 可以应用在并行流上以保持元素顺序 |
2.1 中间操作
下面演示流的操作使用 - 中间操作
public class Demo2 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>( );
list.add(1);
list.add(1);
list.add(2);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
// 方式1: 从集合获得流
Stream<Integer> stream = list.stream( );
/**
* filter是过滤,满足指定的条件数据保留
* forEach是遍历
*/
// 过滤保留偶数
// stream.filter(e -> e % 2 == 0).forEach(e -> System.out.println(e ));
/**
* map 是转换
*/
// 将数字扩大10倍
// stream.map(e -> e * 10).forEach(e -> System.out.println(e ));
/**
* limit限制,只要流中的前几个数据
*/
//stream.limit(2).forEach(s -> System.out.println(s ));
// 跳过
//stream.skip(2).forEach(s -> System.out.println(s ));
// Stream<Integer> s1 = Stream.of(1, 3, 5, 7);
// Stream<Integer> s2 = Stream.of(2, 4, 6, 8);
// // 合并
// Stream<Integer> s3 = Stream.concat(s1, s2);
// s3.forEach(s -> System.out.println(s));
/**
* 终结操作 max
*/
// Optional<Integer> optional = stream.max((o1, o2) -> o1 - o2);
// System.out.println(optional );// 这个Optional中包含结果
// // 需要再取出
// Integer max = optional.get( );
// System.out.println(max );
Integer max = stream.max((o1, o2) -> o1 - o2).get( );
}
}
public class Demo7 {
public static void main(String[] args) {
// Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
// 终结操作,遍历
// stream.forEach(s -> System.out.println(s ));
// filter过滤数据,判断结果为true就保留
// stream.filter(x -> x % 2 == 0).forEach(s -> System.out.println(s));
// map是转换,
// 将流中数据>1的保留,且将它们转换为字符串输出
// stream
// .filter(x -> x > 1)
// .map(x -> String.valueOf(x))
// .forEach(s -> System.out.println(s));
// flatMap 摊平,将两个集合/数组/流转成一个
// Stream<String> java = Stream.of("java", "python");
// List<String> collect = java.flatMap(s -> Arrays.stream(s.split("")))
// .collect(Collectors.toList( ));
//
// System.out.println(collect );
//
// ArrayList<Integer> l1 = new ArrayList<>( );
// l1.add(1);
// l1.add(3);
// l1.add(5);
//
// ArrayList<Integer> l2 = new ArrayList<>( );
// l2.add(2);
// l2.add(4);
// l2.add(6);
//
// ArrayList<List> l3 = new ArrayList<>( );
// l3.add(l1);
// l3.add(l2);
// System.out.println(l3 );
//
// Object l4 = l3.stream( ).flatMap(s -> s.stream( )).collect(Collectors.toList( ));
// System.out.println(l4 );
// Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
// limit 保留前n个,skip 跳过 n个
// stream.limit(4).skip(2).forEach(s -> System.out.println(s ));
}
}
2.3 注意事项
Stream流的操作注意事项
流的操作只能使用一次,也就是说执行过终结操作后不能再继续使用
否则报错报错
IllegalStateException stream has already been closed
使用中间操作,返回新的流
没有终止操作,就不会有结果,换句话说,没有终结操作,中间操作是 不会执行的
public static void test2() {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.filter((e) -> {
System.out.println("正在过滤元素:"+e );
return e % 2 == 0;
});
// 没有终结操作,中间的filter不会执行,输出语句不会执行
}
3、 流的收集
流操作完,将数据流中的数据再返回成数组和集合 --> 这就是收集流
将流收集到集合或数组中
collect() 收集到集合
collect(Collectors.toList( )) 将stream流中的数据,收集到List集合
collect(Collectors.toSet( )) 将stream流中的数据,收集到set集合
toArray 收集到数组
ArrayList<Integer> list = new ArrayList<>( );
list.add(3);
// 获得流
Stream<Integer> stream = list.stream( );
// 先过滤数据只保留偶数
// 后对数据进行降序排序,
// 去除重复元素,
// 将元素转成String类型
// 变成ArrayList<String>返回
List<String> list2 = stream.filter(e -> e % 2 == 0)
.sorted((o1, o2) -> o2 - o1)
.distinct( )
.map(e -> String.valueOf(e))
.collect(Collectors.toList( ));// 收集为List集合