函数式编程 常用类库

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

由于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());
}

断言是正确的

默认方法的三定律

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

Optional

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

  1. Optional.of(..)获取Optional对象
  2. Optional.empty 返回空的对象
  3. Optional.ofNullable 将空值转换成Optional对象
  4. isPresent 表示Optional对象是否有值
  5. orElse 当Optional 对象为空时,该方法提供了一个备选值
  6. 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"));
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值