函数式编程 常用类库

xiaoxiao2021-02-27  411

基本类型和装箱类型的转换

由于Java的泛型都是基于对泛型类型的擦除,所以泛型的参数只能是基本类型对应的装箱类型。

由于装箱类型是对象,因此在内存中存在额外开销。在Java 8 中,仅对 整型 长整型 双浮点型 做了特殊处理

在Stream 类的某些方法对基本类型和装箱类型做了区分

对基本类型做特殊处理的方法在命名上有明确的规范。如果方法返回类型为基本类型,则在基本类型前加To,如ToLongFunction。

如果参数是基本类型,则不加前缀只需类型名即可

如果高阶函数使用基本类型,则在操作后加后缀To 再加基本类型,如mapToLong

这些基本类型都有与之对应的Stream,以基本类型名为前缀,如LongStream。事实上,mapToLong 方法返回的不是一个一般的Stream,而是一个特殊处理的Stream。在这个特殊的Stream 中,map 方法的实现方式也不同,它接受一个LongUnaryOperator 函数,将一个长整型值映射成另一个长整型值

通过一些高阶函数装箱方法,如mapToObj,也可以从一个基本类型的Stream 得到一个装箱后的Stream,如Stream<Long>。

exp:

public class BaseTypeTest { //T->long private ToLongFunction<String> toLongFunction; //long->T private LongFunction<String> longFunction; @Before public void setUp() throws Exception { toLongFunction = new ToLongFunction<String>() { @Override public long applyAsLong(String value) { return value.length(); } }; } @Test public void test() throws Exception { List<String>strings = Arrays.asList("123434","2312324","32323"); LongSummaryStatistics longSummaryStatistics = strings.stream().mapToLong(toLongFunction).summaryStatistics(); System.out.printf("Max: %d, Min: %d, Ave: %f, Sum: %d", longSummaryStatistics.getMax(), longSummaryStatistics.getMin(), longSummaryStatistics.getAverage(), longSummaryStatistics.getSum()); }

输出:

Max: 7, Min: 5, Ave: 6.000000, Sum: 18

重载解析

private interface IntegerBiFunction extends BinaryOperator<Integer> { } private void overloadedMethod(BinaryOperator<Integer> Lambda) { System.out.print("BinaryOperator"); } private void overloadedMethod(IntegerBiFunction Lambda) { System.out.print("IntegerBinaryOperator"); }

同时存在多个重载方法时,哪个是“最具体的类型”可能并不明确

Lambda 表达式作为参数时,其类型由它的目标类型推导得出,推导过程遵循如下规则:

如果只有一个可能的目标类型,由相应函数接口里的参数类型推导得出;如果有多个可能的目标类型,由最具体的类型推导得出;如果有多个可能的目标类型且最具体的类型不明确,则需人为指定类型。

默认方法

使用default定义接口默认方法

public interface Parent { public void message(String body); public default void welcome() { message("Parent: Hi!"); } public String getLastMessage(); } }

ParentImpl类仅仅实现的Parent接口,没有实现welcome 方法

@Test public void parentDefaultUsed() { Parent parent = new ParentImpl(); parent.welcome(); assertEquals("Parent: Hi!", parent.getLastMessage()); }

断言是正确的

默认方法的三定律

类胜于接口。 如果在继承链中有方法体或抽象的方法声明,那么就可以忽略接口中定义的方法。子类胜于父类。 如果一个接口继承了另一个接口,且两个接口都定义了一个默认方法, 那么子类中定义的方法胜出。没有规则三。 如果上面两条规则不适用,子类要么需要实现该方法,要么将该方法声明 为抽象方法。

Optional

Optional 是为核心类库新设计的一个数据类型,用来替换null 值。

Optional.of(..)获取Optional对象Optional.empty 返回空的对象Optional.ofNullable 将空值转换成Optional对象isPresent 表示Optional对象是否有值orElse 当Optional 对象为空时,该方法提供了一个备选值orElseGet 该方法接受一个Supplier对象,只有在Optional对象真正为空时才会调用。 @Test public void testOptional() throws Exception { //1.Optional.of Optional<String> s = Optional.of("a"); assertEquals("a", s.get()); //2.Optional.empty 返回空的对象 //3.Optional.ofNullable 将空值转换成Optional对象 //4.isPresent 表示Optional对象是否有值 Optional<String> empty = Optional.empty(); Optional<String> alsoEmpty = Optional.ofNullable(null); assertFalse(empty.isPresent()); assertFalse(alsoEmpty.isPresent()); assertTrue(s.isPresent()); //5.orElse 当Optional 对象为空时,该方法提供了一个备选值 //6.orElseGet 该方法接受一个Supplier对象,只有在Optional对象真正为空时才会调用。 assertEquals("b", alsoEmpty.orElse("b")); assertEquals("c", alsoEmpty.orElseGet(() -> "c")); }
转载请注明原文地址: https://www.6miu.com/read-1468.html

最新回复(0)