函数式编程
1.函数式接口
?都只有一个未实现的方法的接口 一般通过FunctionalInterface来表明某个接口是一个函数式接口 。
1.入门
方法- accept()
只有输入没有输出
- Consumer对象的定义
传统方式:实现内部类
Consumer c = new Consumer(){
@Override
public void accept(Object o){
System.out.println(o);
}
}
Java8 :函数接口
//使用这种写法时,编译器会将这段函数作为函数式接口中的唯一方法的实现,当然这种写法只针对接口中有且只有一个抽象方法,如果存在多个抽象方法编译器就无法知道这段函数是来实现的哪个方法。
Consumer c = (o) -> {
System.out.println(o);
};
// '='后面的可以看做方法的实现
// 函数体只有一句话,可以简化为
Consumer c = (o) -> System.out.println(o);
- 输入:
->
前面的(o)
即是该抽象方法需要传递进来的参数,如果没有参数,可以直接写为**()
** - 函数体:即用
{}
包起来的内容 - 输出:函数式编程可以有返回值也可以没有,如果有返回值的时候,要在
函数体
中return。
2.Consumer
? 消费者,只有参数进来,没有返回值。 只有输入没有输出
eg: Consumer consumerDemo = (o) -> {System.out.println(o);};
方法- accept()
//Consumer提供该接口,由使用者自行来实现
方法- andThen()
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
//return 中使用函数式接口返回的会是一个什么呢?
}
3.Function
? 函数,有输入有输出
初始化的时候需要指定输入和输出的类型
eg:Function<Integer,Integer> functionDemo = (o) -> { return o*3};
方法- apply()
实现逻辑的方法,与上面的
accept()
相同
方法-compose()
将传递进来的Function的apply()的返回值作为参数,再执行自己的apply()
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
//此处将先执行参数的apply(),再执行自己的apply()
return (V v) -> apply(before.apply(v));
}
方法-andThen()
将自己apply()结果传递到参数的apply() 进行执行
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
//此处将自己的apply结果传递到参数after的apply方法中
return (T t) -> after.apply(apply(t));
}
方法-identify()
返回的结果与传入的参数一致
static <T> Function<T, T> identity() {
return t -> t;
}
4.Predicate
?断定,根据输入值来做逻辑判断
初始化的时候需要指明传入参数类型
eg: Predicate predicateDemo = (o) -> {o.equals(2);};
方法-test()
判定基本方法
boolean test(T t);
方法-and()
判定条件&&
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
//判断自己和参数的test()是否同时为true
return (t) -> test(t) && other.test(t);
}
方法-or()
判定条件 ||
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
//判定自己和参数的test()是否有一个为true
return (t) -> test(t) || other.test(t);
}
方法-isEqual()
判定是否相同 通过传入类型的equals方法判断
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
//通过传入参数targetRef的类型的equals方法进行判断
}
方法-negate()
对原来的结果取反
default Predicate<T> negate() {
return (t) -> !test(t);
}
2.函数式编程接口的使用
1.Stream
可以对元素进行一系列的操作,也可以支持对某些操作进行并发处理
-
初始化方法
- 创建空的Stream对象
返回一个无限有序值的Stream对象,第一个元素为seed,第二个为f.apply(seed),
第N个元素是f.apply(n-1个元素的值)。在遇到终止方法前是不会真正执行的,所以一般与limit等方法一起使用
Stream stream = Stream.empty();
- 通过集合类中的stream或者parallerStream方法创建
返回一个有限值的Stream,终止条件有hasNext()来断定
List<String> list = Arrays.asList("c", "o", "l", "o","r"); Stream listStream = list.stream(); //获取串行的Stream对象 Stream parallelListStream = list.parallelStream(); //获取并行的Stream对象
- 通过Stream中的of()创建
//本质上是通过Arrays.stream(value)来创建 Stream s1 = Stream.of("test"); Stream s2 = Stream.of(1,2,3,4,5);
- 通过Stream的iterate方法创建
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}
- 通过Stream的generate()方法创建
Stream stream = Stream.generate(() -> { return (int)(Math.random()*10); });
6.通过Stream的concat方法连接两个Stream
2.Stream使用
Stream对象提供多个非常有用的方法,这些方法可以分成两类:
中间操作:将原始的Stream转换成另外一个Stream;如filter返回的是过滤后的Stream。
终端操作:产生的是一个结果或者其它的复合操作;如count或者forEach操作
filter
用于对Stream中的元素过滤,返回一个过滤后的Stream
List<String> list = Arrays.asList("c", "o", "l", "o","r");
list.stream().filter((o) -> o.equals("o")).forEach(System.out::print);
map
接收一个Function参数,用Fucntion的apply()来对Stream中的每一个元素进行操作,返回的Stream中的元素都是经过Function处理后的
//List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,7,8,9);
//integerList.stream().map(o -> o*2).forEach(System.out::print);
Stream<Integer> integerList =Stream.of(1,2,3,4,5,6,7,8,9);
integerList.map(o -> o*2).forEach(System.out::print);
flatMap
接收一个Function参数,将原Stream中的每个元素传入Function中进行处理,其中每个元素处理后都返回一个有多个元素的Stream对象,然后再把这些Stream对象中的所有元素组合成一个统一的Stream再返回。
List<String> list = Arrays.asList("color", "olor", "lor", "or","r");
list.stream().flatMap(o -> Stream.of(o.split(""))).forEach(o -> System.out.print(o+" "));
takeWhile (Java 9)
如果是有序的,返回通过Predicate判定后的最长序列,如果是无序的,返回通过Predicate判定后的序列。
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa", "taaa");
//以下结果将打印: "test", "t1", "t2", "teeeee",最后的那个taaa不会进行打印
s.takeWhile(n -> n.contains("t")).forEach(System.out::println);
dropWhile(Java 9)
如果是有序的,返回除了通过Predicate判定所匹配的最长序列的其他所有元素;如果是无序的 , 将会返回通过Predicate判定后不匹配的所有元素的序列。
Stream<String> s = Stream.of("test", "t1", "t2", "teeeee", "aaaa", "taaa");
//以下结果将打印:"aaaa", "taaa"
s.dropWhile(n -> n.contains("t")).forEach(System.out::println);
reduce和collect 待补充
3.Optional
单例模式
用于简化Java中对空值的判断处理,以防止出现空指针异常,其实是对一个变量进行封装,类中有个属性value,就是该变量的值。
- Optional对象初始化
- empty方法
Optional o = Optional.empty();
- of方法
//传入的value必须为非空值,否则会抛出空指针异常
Optional o = Optional.of("demo");
- ofNullable
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
//传入的value可以为空值,为空的时候返回empty方法
Optional o = Optional.of("demo");
4.Optional方法使用
ifPresent
判断结果不为空后使用,为空时不进行处理
Optional<String> optional = Optional.ofNullable(test());
optional.ifPresent(o -> System.out.println("test() return not null:"+o));
orElse
判断为空时提供默认值,返回值类型为String
Optional<String> optional = Optional.ofNullable(null);
String s = optional.orElse("new value");
orElseThrow
判断为空时,抛出异常,orElseThrow() 参数为Supplier,生产者(只有输出没有输入)
Optional<String> optional = Optional.ofNullable(null);
optional.orElseThrow(() -> new Exception("wrong"));