Java函数式编程(四)JDK8对库的增强

Java函数式编程(四)JDK8对库的增强

3 函数式编程特性的应用

3.3 JDK8对库的增强

为了在Java中支持函数式编程,JDK除了增加上面列举的这些新的函数和Stream接口,类以外,还需要对既存的接口和类进行增强,例如给Collection接口增加stream()方法。变更接口带来的后果就是JDK8之前的程序在JDK8上不能构建,例如缺少stream()方法的实现。所以JDK8还要考虑向后兼容问题,体现在一下几个方面:

3.3.1 接口增加默认方法

接口增加默认方法解决了接口变更向后兼容的问题。例如:
为了支持Stream, Collection接口中增加了如下默认方法:

	default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
	
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
    
	@Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }

默认方法式支持多态的。
在多层类继承结构中,类中的默认方法的实现总是优先覆盖父类或接口中的实现.

3.3.2 接口的多重继承

接口是可以多重继承的,如果多个接口包含相同签名的默认方法,子类无法确定继承哪个,编译会报错。子类需要自己实现个个方法,在具体的实现中选择调用哪一个父类的实现。可以使用如下的增强的super语法:

public class child implements Interface1, Interface2 {
	@Override
	public void method1() {
		Interface1.super.method1();
	}
}

如何确定在多重继承的体系结构中,子类中的默认方法是哪一个?有如下3原则:
1.类胜于接口
2.子类胜于父类
3.如果以上两个原则不适用,那么子类需要自己实现,或者将该方法声明为抽象方法

3.3.3 接口的静态方法

JDK8建议将接口级别相关的方法放在接口中,也就是接口中的静态方法。
例如在Stream接口中工厂方法:

	public static<T> Stream<T> of(T t) {
        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
    }

3.3.4 Optional类

之前看到,在Stream接口中,reduce方法有两个实现,其中一个的返回值为Optional类型

	Optional<T> reduce(BinaryOperator<T> accumulator);

Optional是为和兴类库设计的一个新的数据类型,用来替换null值。
在上例中,如果Stream是空的,而且此接口并没有指定初始值,那么reduce方法并不会直接返回null,而是返回一个代表empty的Optional对象,用来驱使程序员检查返回值是否为空,从而避免了NullPointerException带来的弊端。

修饰符和返回值方法描述
static Optionalempty()返回一个空的 Optional 实例。
booleanequals(Object obj)指示其他对象是否“等于”此Optional对象.
Optionalfilter(Predicate<? super T> predicate)如果存在一个值,并且该值与给定的谓词匹配,则返回一个描述该值的 Optional,否则返回一个空的 Optional。
Optionalmap(Function<? super T,? extends U> mapper)如果存在值,则将提供的映射函数应用于该值,如果结果为非空,则返回描述结果的Optional对象。
OptionalflatMap(Function<? super T,Optional> mapper)如果存在值,则对其应用提供的 Optional-bearing 映射函数,返回该结果,否则返回空 Optional.此方法类似于 map(Function),但提供的映射器是其结果已经是 Optional 的映射器,如果被调用,flatMap 不会用附加的 Optional 包装它。
Tget()如果此 Optional 中存在值,则返回该值,否则抛出 NoSuchElementException。
inthashCode()返回当前值的哈希码值(如果有),如果没有值,则返回 0(零)。
voidifPresent(Consumer<? super T> consumer)如果存在值,则使用该值调用指定的消费者,否则什么也不做。
booleanisPresent()如果存在值则返回真,否则返回假。
static Optionalof(T value)返回具有指定当前非空值的 Optional。
static OptionalofNullable(T value)返回一个描述指定值的Optional,如果非null,否则返回一个空Optional。
TorElse(T other)如果存在则返回值,否则返回other。
TorElseGet(Supplier<? extends T> other)如果存在则返回该值,否则调用 other 并返回该调用的结果。
TorElseThrow(Supplier<? extends X> exceptionSupplier)返回包含的值,如果存在,否则抛出由提供的Supplier创建的异常。
StringtoString()返回此 Optional 适合调试的非空字符串表示形式。

Optional示例:

package com.qupeng.fp.lambda;

import java.util.NoSuchElementException;
import java.util.Optional;

public class TestOptional {
    public static void main(String[] args) {
        // 工厂方法1:empty
        Optional<String> optionalStr = Optional.empty();
        if (!optionalStr.isPresent()) {
            try {
                optionalStr.get();
            } catch (NoSuchElementException elementException) {
                System.out.println(elementException);
            }
            System.out.println(optionalStr.orElse("String from orElse method."));
            System.out.println(optionalStr.orElseGet(() -> "String from orElseGet method."));
        }

        // 工厂方法2: ofNullable
        optionalStr = Optional.ofNullable(null);
        try {
            optionalStr.orElseThrow(RuntimeException::new);
        } catch (RuntimeException exception) {
            System.out.println(exception);
        }

        // 工厂方法3: of
        try {
            optionalStr = Optional.of(null);
        } catch (NullPointerException exception) {
            System.out.println(exception);
        }

        // 工厂方法3: of
        optionalStr = Optional.of("It's a optional String.");
        optionalStr.ifPresent(System.out::println);

        // map方法
        Optional<Integer> optionalInt = optionalStr.map(str -> {
            try {
                return Integer.valueOf(str);
            } catch (NumberFormatException exception) {
                return null;
            }
        });

        if (!optionalInt.isPresent()) {
            System.out.println("It's not a integer.");
        }

        // flatMap方法
        optionalStr = Optional.of("99");
        optionalInt = optionalStr.flatMap(str -> {
            try {
                return Optional.of(Integer.valueOf(str));
            } catch (NumberFormatException exception) {
                return Optional.empty();
            }
        });

        if (optionalInt.isPresent()) {
            System.out.println(optionalInt.get());
        }

        // filter方法
        optionalInt.filter(integer -> integer > 0);
        if (optionalInt.isPresent()) {
            System.out.println(optionalInt.get());
        } else {
            System.out.println("The number in Optional is greater than 99");
        }
    }
}
OptionalInt
OptionalLong
OptionalDouble

3.3.5 方法引用

方法引用是Lambda表达式一种简写的方式,通过方法的名字来指向一个方法,使用一对冒号 :: 作为运算符。例如:Consumer consumer = System.out::println。
任何使用Lambda表达是的地方都可以使用方法引用替代,它可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用有四种基本方式:
构造器引用:

  1. 它的语法是Class::new,或者更一般的Class::new实例如下:
	Supplier<String> supplier = String::new;
  1. 静态方法引用:它的语法是Class::static_method,实例如下:
	IntFunction<String> intFunction = Integer::toString;
  1. 特定类的任意对象的方法引用:它的语法是Class::method实例如下:
	Consumer<Integer> action = Integer::doubleValue;

这种情况比较特殊,函数接口的形参列表和被引用方法的形参列表不是完全一致的。函数接口的第一个形参对应调用类实例方法的那个对象,所以函数接口的形参列表比类实例方法多第一个参数。

	void accept(T t); // t就是调用方法引用的那个对象
	public abstract double doubleValue(); // 实际的调用可以看作:t.doubleValue()
  1. 特定对象的方法引用:它的语法是instance::method实例如下:
	Integer int99 = Integer.valueOf(99);
	IntFunction<Integer> intFunction2 = int99::compareTo;

简答的示例:

package com.qupeng.fp.lambda;

import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.Supplier;

public class TestMethodRef {
    public static void main(String[] args) {
        // 构造函数引用
        Supplier<String> supplier = String::new;
        String helloWorld = supplier.get();
        System.out.println(helloWorld);

        // 静态方法引用
        IntFunction<String> intFunction = Integer::toString;
        String str = intFunction.apply(99);
        System.out.println(str);

        // 特定类的任意对象的方法引用1
        Consumer<Integer> action = Integer::doubleValue;
        Arrays.asList(1, 2, 3).forEach(action);

        // 特定类的任意对象的方法引用2
        BiFunction<Integer, Integer, Integer> biFunction = Integer::compareTo;
        int result = biFunction.apply(100, 99);
        System.out.println(result);

        // 特定对象的方法引用
        Integer int99 = Integer.valueOf(99);
        IntFunction<Integer> intFunction2 = int99::compareTo;
        result = intFunction2.apply(100);
        System.out.println(result);
    }
}

3.3.6 Map

JDK 8中为Map接口新增了三个默认方法,三个高阶函数。用来扩展获取元素时的一些行为,例如取不到时重新计算:

	default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
	default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
	default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

简单的示例:

package com.qupeng.fp.lambda;

import java.util.HashMap;
import java.util.Map;

public class TestMap {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap();
        map.put("a", 2);
        map.put("b", 0);
        map.put("c", 3);
        
        // 不管value是否存在,都重新计算一个值
        Integer value1 = map.compute("a", (str, integer) -> {
            if (null == integer || 1 !=  integer) {
                return Integer.valueOf(1);
            } else {
                return integer;
            }
        });
        
        // value不存在,计算一个新值
        Integer value2 = map.computeIfAbsent("b", s -> {
            if (s.equals("b")) {
                return 2;
            } else {
                return 0;
            }
        });
        
        // value存在,递增当前value
        Integer value3 = map.computeIfPresent("c", (str, integer) -> ++integer);
        System.out.println("" + value1 + ", " + value2 + ", " + value3);
        System.out.println(map);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值