6.1 接口

接口概念

接口是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。设计目的是解决多继承的问题

接口中所有方法时 public 不用现实声明

java.lang.Comparable <T> 有方法

int compareTo(T other) 当前对象与 other 比较,对象小于 other 则返回负值;相等则返回 0 ;否则返回正值。

java.util.Arrays 有方法

static void sort(Object[] a) 使用 mergesort 算法对数组中的元素进行排序。要求数组中的元素属于实现了 Compareable 接口的类,并且元素之间是可比较的。

语言标准规定:对于任意的 x 和 y ,实现必须能够保证 sgn(x.compareTo(y)) = -sgn(y.compareTo(x))。(也就是说,如果 y.compareTo(x) 抛出一个异常,那么x.compareTo(y) 也应该抛出一个异常。)这里的“sgn”是一个数值的符号:如果 n 是负值,sgn(n) 等于-1;如果 n 是0,sgn(n) 等于0;如果 n 是正值,sgn(n)等于1简单地讲,如果调换compareTo的参数,结果的符号也应该调换(而不是实际值)

与 equals 方法一样,在继承过程中有可能会出现问题,因为涉及到子类与父类比较,子类之间的比较。可以在比较对象前,检查是否属于同一类。或者在父类中将比较方法定义为 final,不允许子类覆盖。

接口特性

接口不能实例化,但可以声明变量引用实体类的对象。接口中不能包含实例域,可以包含常量。 接口中的域自带 public static final。 可以使用静态方法,用来替代伴随工具类。

默认方法

default 方法可以在接口内添加方法的具体实现。默认方法的一个重要用途是接口演化,给已经被使用的接口添加方法时,如果没有提供默认实现,则实现此接口的类必须去实现新的方法,破坏了兼容性。

默认方法与基类的方法冲突时,同名且有相同类型参数的默认方法会被忽略。

如果一个超接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型 (不论是否是默认参数)相同的方法, 必须覆盖这个方法来解决冲突。

两个接口如何冲突并不重要。 如果至少有一个接口提供了一个实现, 编译器就会报告错误, 而程序员就必须解决这个二义性。

6.2 接口示例

回调

一种程序设计模式,可以指出某个特定事件发生时应该采取的动作。

public class TimePrinter implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("At the tone, the time is "+new Date());
Toolkit.getDefaultToolkit().beep();
}
}

TimePrinter 实现了接口 ActionListener 实现了 actionPerformed 方法,即告诉程序发生了某件事调用了这个方法时,进行如何操作。

Comparator 接口

有的时候需要自定义一些比较规则用于数组排序 Arrays.sort(T[] a, Comparator<? super T> c)

则可以定义一个类实现 Comparator 接口,实现 compara 方法

对象克隆

Object 实现 clone 方法,只是一个个域进行拷贝。如果对象中所有的域都是基本类型,拷贝没有问题。但如果对象包含子对象的引用,拷贝域则会得到相同对象的另一个引用。这样一来,克隆与原对象仍然会共享一些信息。 如果共享的子对象是不可改变的,这种共享是安全的。或者在对象生命周期中,子对象所包含的都是不变的常量。

但是通常情况下,子对象都是可变的,必须重新定义 clone 方法来建立一个深拷贝,同时克隆所有子对象。如果需要使用 clone 方法,必须实现 Cloneable 接口,重新定义 clone 方法,并指定访问权限为 public。

即使 clone 的默认实现能够满足要求,还是需要实现 Cloneable 接口,将 clone 重新定义为 public ,再调用 super.clone()。

6.3 Lambda 表达式

将一个代码块传递到某个对象,代码块将在未来某个时候调用。Java 中传递一段代码并不容易,不能直接传递代码段,必须构造一个对象,这个对象的类需要有一个方法能包含所需的代码。

lambda 表达式语法

lambda 表达式就是一个代码块,以及必须传入代码的变量规范。

参数,箭头(->)以及一个表达式。如果代码要完成的计算无法放到一个表达式中,可以像写方法一样,把代码放到{}中并包含显式的 return 语句。

即使没有参数仍然要提供空括号,如果能推导出一个 lambda 表达式的参数类型,则可以忽略其类型。如果方法只有一个参数,且参数类型可以推导出来,小括号也可以省略。无需指定 lambda 表达式的返回类型,lambda 表达式的返回类型总是会由上下文推导得出。

函数式接口

对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个 lambda 表达式。这种接口称为函数式接口(functional interface)

通常遇到方法需要一个标记接口为参数时,会创建一个类去实现接口,再用接口类型的变量引用类的对象作为参数。更直接一点的办法是,使用一个匿名类实现接口,并实现方法。而使用 lambda表达式则直接传入方法,对应的就是函数式接口的那个方法的实现。

方法引用

例如下面代码的 lambda 表达式是等价的,System.out::println 是方法引用。

        Timer t = new Timer(1000,event -> System.out.println(event));
Timer t1 = new Timer(1000,System.out::println);

要用 :: 操作符分隔方法名与对象或类名。主要有 3 种情况:

  • object::instanceMethod
  • Class::staticMethod
  • Class::instanceMethod

    前两种情况中,方法引用等价于提供参数的 lambda 表达式。例如
System.out::println //等价于 x -> System.outprintln(x)
Math::pow //等价于(x,y) ->Math.pow(x,y)

第三种情况,第 1 个参数会成为方法的目标。例如

String::compareToIngoreCase //等价于(x,y) ->x.compareToIgnoreCase(y)

可以在方法引用中使用 this 例如

this::equal //等价于 x ->this.equal(x)。

使用 super 也是合法的。

构造器引用

与方法引用类似,不过方法名为new

int[]::new //等价于 x-> new int[x]
变量作用域

lambda 表达式可以捕获外围作用域中变量的值。在 Java 中,要确保所捕获的值是明确定义的,有一个限制,即 lambda 表达式中只能引用不会改变的变量。lambda 表达式中捕获的变量必须实际上是最终变量,即变量初始化后不会再为它赋值。

处理 lambda 表达式

使用 lambda表达式的重点是延迟执行。方法在被当做函数时接口调用时才会执行。可能有下列原因需要延迟执行

  • 在一个单独的线程中运行代码
  • 多次运行代码
  • 在算法的适当位置运行代码
  • 发生某种情况时执行代码
  • 只在必要时才运行代码

    下表是常用的函数式接口
函数式接口 参数类型 返回类型 抽象方法名 描述 其他方法
Runnable void run 作为无参数或返回值的动作运行
Supplier<T> T get 提供一个 T 类型的值
Consumer<T> T void accept 提供一个 T 类型的值 andThen
BiConsumer<T,U> T,U void accept 处理 T 和 U 类型的值 andThen
Function<T,R> T R apply 有一个 T 类型参数的函数 compose, andThen, identity
BiFunction<T,U,R> T,U R apply 有 T 和 U 类型参数的函数 andThen
UnaryOperation<T> T T apply 类型 T 上的一元操作符 compose, andThen, identity
BinaryOperatior<T> T,T T apply 类型 T 上的二元操作符 andThen, maxBy, minBy
Predicate<T> T boolean test 布尔值函数 and, or, negate, isEqual
BiPredicate<T> T,U boolean test 有两个参数的布尔值函数 and, or, negate

6.1 接口 - 6.3 lambda表达式的更多相关文章

  1. [二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

    函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type use ...

  2. Java1.8新特性——接口改动和Lambda表达式

    Java1.8新特性——接口改动和Lambda表达式 摘要:本文主要学习了Java1.8的新特性中有关接口和Lambda表达式的部分. 部分内容来自以下博客: https://www.cnblogs. ...

  3. Lambda表达式与函数式接口

    Lambda表达式的类型,也被称为目标类型(targer type),Lambda表达式的目标类型必须是"函数式接口(functional interface)".函数式接口代表只 ...

  4. java8 Lambda表达式的新手上车指南(1)--基础语法和函数式接口

    背景 java9的一再推迟发布,似乎让我们恍然想起离发布java8已经过去了三年之久,java8应该算的上java语言在历代版本中变化最大的一个版本了,最大的新特性应该算得上是增加了lambda表达式 ...

  5. Java核心技术-接口、lambda表达式与内部类

    本章将主要介绍: 接口技术:主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口. lambda表达式:这是一种表示可以在将来的某个时间点执行的代码块的简洁方法. 内 ...

  6. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  7. 函数式接口 & lambda表达式 & 方法引用

    拉呱: 终于,学习jdk8的新特性了,初体验带给我的感觉真爽,代码精简的不行,可读性也很好,而且,spring5也是把jdk8的融入到血液里,总之一句话吧,说的打趣一点,学的时候自己难受,学完了写出来 ...

  8. java8 Lambda 表达式和函数式接口快速理解

    前言 接上篇文章 java8 新特性 由于上篇过于庞大,使得重点不够清晰,本篇单独拿出 java8 的 Lambda 表达式和函数式接口说明. Lambda 表达式 lambda 表达式其实就是使用了 ...

  9. 死磕Lambda表达式(四):常用的函数式接口

    失去人性,失去很多:失去兽性,失去一切.--<三体> 在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口.它们主要 ...

随机推荐

  1. 洛谷 P6851 【onu】贪心

    题目描述 题目传送门 分析 因为小 \(D\) 打出的牌与小 \(C\) 打出的牌花色必须相同,所以我们需要按照花色分类讨论 对于某一种花色 如果小 \(C\) 没有这种花色的牌但是小 \(D\) 有 ...

  2. 关于IPA文件重签名后如何跟踪管理APP的技术探讨和实践演示

    前言:开发iOS的朋友都知道,在功能开发完成后,我们就会用申请的苹果账号在后台做证书配置,然后提交到AppStore,但是也有部分APP我们不需要提交到AppStore,比如内部测试用的APP.定制给 ...

  3. Prometheus 系列开篇:为什么要学 Prometheus ?

    「Prometheus 系列开篇:为什么要学 Prometheus ?」首发于[陈树义]公众号,点击跳转到原文https://mp.weixin.qq.com/s/HCS6X3l6nVBw_hAnd6 ...

  4. Git软件操作过程

    一.下载 Git 二.下载Git小乌龟-TortoiseGit 三.汉化-去官网下载,官网地址 https://tortoisegit.org/download/

  5. 性能测试-CPU瓶颈分析的思路

    CPU(中央处理器),是电子计算机的主要设备之一,电脑中的核心配件.CPU作为计算机系统的运算和控制核心,是信息处理.程序运行的最终执行单元.CPU的功效主要为处理指令.执行操作.控制时间.处理数据. ...

  6. docker registry 记录

    部署 运行下面命令获取registry镜像 docker pull registry 下载到的版本默认为 docker.io/registry latest 将registry镜像运行并生成一个容器 ...

  7. docker启动服务---------------kafka+zookeeper

    docker run -d --name zookeeper -p 2181:2181 wurstmeister/zookeeperdocker run -d --name kafka -p 9092 ...

  8. Docker下部署springboot项目

    1.背景 如何在docker容器环境下部署一个springboot项目? 2.具体步骤 第一步:准备一个springboot项目的xxxx.jar包 jar包中用于测试的一个接口如下 第二步:编写Do ...

  9. nginx优化:配置gzip压缩页面提高访问速度(nginx1.18.0)

    一,为什么nginx要使用gzip 1,压缩的作用: 页面使用gzip压缩之后, 页面大小可以压缩到原来的1/7左右, 传输速度和页面打开时间都可以大幅度提高, 有利于用户访问页面体验的提升 2,Ng ...

  10. centos8平台编译安装nginx1.18.0

    一,nginx的官网: http://nginx.org/ 说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest 对应的源码 ...