接口
接口是双方,即服务提供方和想让它们的对象对服务是可用的那些类,之间约定的一种机制。
声明一个接口
public interface IntSequence{ //不提供实现,则该方法为抽象方法,且默认为公有方法,不必为hasNext和next声明为public
boolean hasNext();
int next();
}
实现接口
public class SquareSequence implements IntSequence{//implements 指示SquareSequence类想要遵从 IntSequence 接口
private int i;

public boolean hasNext(){//实现类必须将接口方法声明为public,因为默认情况下,它们在包级别可访问
return true;
}

public int next(){
i++;
return i*i;
}
}
//返回无穷多个平方元素,并且一个对象可以一次一个的处理所有的平方元素

SquareSequence s = new SquareSequence();
double avg = avgrage(s,100);

另外一个IntSequence的实现DigitSequence
public class DigitSequence implements IntSequence{

private int number;

public DigitSequence(int n){
number = n;
}

@Override
public boolean hasNext() {
return number!=0;
}

@Override
public int next() {
int result = number%10;
number = number/10;
return result;
}

public int rest(){
return number;
}
}
当子类型T的任何值不需要转换就能赋值给父类型S的变量时,类型S是类型T(子类)的父类,例如,IntSequence 接口是DigitSequence类的父类。
虽然声明接口类型的变量是可能的,但是永远不会存在类型为接口的对象。所有对象都是类的实例。
IntSequence digits = new DigitSequence(9876);
System.out.println(average.average(digits,100));

从父类转换为子类,即当知道父类型IntSequence存储的就是子类型DigitSequence对象时。
IntSequence s = ...;
DigitSequence digits = (DigitSequence) s;
System.out.println(digits.rest());
这种情况下转换是必须的因为rest方法为digitSequence所特有的。
当然最好在强制转换前使用instantof来避免转换异常。
if(s instantof DigitSequence){
DigitSequence digits = (DigitSequence) s;
...
}

继承接口
public interface Closeable{
void close();
}
public interface Channel extends Closeable{
boolean isOpen();
}
即若想实现channel接口需要提供两个方法。

实现多个接口,可以在implements后面添加多个接口。

常量
定义在接口内的任何变量自动为 public static final

静态方法和默认方法(均在java1.8后可以实现)
public interface IntSequence {

public int next();

public static IntSequence digitsOf(int n){ //静态方法
return new DigitSequence(n);
}

default boolean hasNext(){ //默认方法
return true;
}

解决默认方法冲突
public interface Identified {
default int getID(){return Math.abs(hashCode());}
}
public interface Person {
String getName();
default int getID(){return 0;}
}
public class Employee implements Identified,Person{
@Override
public String getName() {
return null;
}

@Override
public int getID() {
return Person.super.getID();//使用super关键字,可以调用父类型的方法。
}

lambda表达式(匿名函数,没有函数名称的函数)
用处:增强可读性,并且使代码更加简洁
同时当编译器可以推断出变量类型时,可以省略()内的变量类型,且无需为lambda表达式指定返回类型
Runnable task1 = new Runnable() {
@Override
public void run() {
System.out.println("not Lambda");
}
};

Runnable task2 = ()->{System.out.println("Lambda");};

对于Arrays.sort方法,该方法的第二个参数要求是一个comparator接口。
Arrays.sort(strings,(x,y)->x.compareToIgnoreCase(y));
Arrays.sort(strings,String::compareToIgnoreCase);//方法引用,与上式等同
对于类似于 操作符::将方法名称与类或对象名称分隔开有以下三种形式
1. 类::实例方法 比如:String::compareToIgnoreCase 与(x,y)->x.compareToIgnoreCase(y)
2. 类::静态方法 比如:Object::isNull 与x->Object.isNull(x)
3. 对象::实例方法 比如:System.out:;println 与System.out.println(x)
构造函数引用于方法引用类似,区别在于引用的方法名称都是new 比如 Employee::new

使用lambda表达式的目的
1.实现延迟执行 (在另一个单独线程中运行代码、多次运行、恰当时刻运行(排序中比较操作的执行))
多次执行
public static void repeat(int n,Runnable r){
for (int i=0;i<n;i++)r.run();
}

repeat(2,()->System.out.println("ll"));

带有参数的lambda表达式使用
public static void repeat(int n,IntConsumer r){
for (int i=0;i<n;i++)r.accept(i);
}

public interface IntConsumer{
void accept(int value);
}

repeat(10,i->System.out.println("Countdown:"+(9-i)));
2.选择函数式接口
大多数编程语言的函数类型都是结构化的。比如为了将两个字符串映射到一个整数的函数。需要使用类似Function<String,String,Integer>或者(String,String)->int
常用函数式接口
函数式接口 参数类型 返回类型 抽象方法名称 描述 其他方法
Runnable none void run 执行一个没有参数或返回值的操作
Supplier<T> none T get 提供类型为T的值
Consumer<T> T void accept 处理T类型的值
BiConsumer<T,U> T,U void accept 处理T类型和U类型的值
Function<T,R> T R apply 参数类型为T的函数
BiFunction<T,U,R> T,U R apply 参数列行为T,U的函数
UnaryOperator<T> T T apply 对类型T进行一元操作
BinaryOperator<T> T,T T apply 对类型T进行二元操作
Predicate<T> T boolean test 布尔值函数
BiPredicate<T,U> T,U boolean test 带有两个参数的布尔值函数
3.实现自己的函数式接口
@FunctionalInterface //注释标记函数式接口
public interface PixelFunction{ //实现(int,int)-> color
Color apply(int x,int y);
}

lambda表达式的作用域
lambda表达式的方法体与嵌套代码块有着相同的作用域,因此,也适用同样的命名冲突和屏蔽规则。在lambda表达式中不允许声明一个与局部变量同名的参数或局部变量
int f;
Comparator<String> comparator = (f,s)->f.length()-s.length(); //f与上面的int f重名。

访问来自闭包作用域的变量
public static void repeat(String msg ,int count){
Runnable r = ()->{
for (int i =0;i<count;i++){//将lambda表达式转变为带有一个方法的对象,这样自由变量的值就可以复制到带对象的实例变量中
System.out.println(msg);
}
};
new Thread(r).start();
}
lambda表达式有三个部分: 1.代码块 2.参数 3.自由变量的值(既不是参数变量也不是代码内部定义的变量)
描述带有自由变量的代码块的技术名词是闭包,在java中,lambda表达式就是闭包。
值得注意的是lambda表达式可以捕获闭合作用域的变量值而不是变量。
public static void repeat(String msg ,int count){
for(int i = 0;i<count;i++){
new Thread(()->{System.out.println(i);});//不能捕获i,因为i会变化,lambda表达式只能访问来自闭合作用域的final局部变量。
}
}

public static void repeat(String[] msg ,int count){
for(String arg:msg){
new Thread(()->{System.out.println(msg);}).start();
//这个是可以的,因为每一次迭代都会创建一个新的arg变量,作用域是单个循环,而上面的i的作用域是整个循环
}
}
值得注意的是,lambda表达式不能改变任何捕获的变量。例如修改上面的arg

高阶函数
1. 返回函数的方法
public static Comparator<String> compareInDirection(int direction){
return (x,y)->direction*x.compareTo(y);
}
调用 compareInDirection(1)产生升序比较器, 调用 compareInDirection(-1)产生降序比较器
结果可以传递个另一个期望这个接口的方法(Arrays.sort)
Arrays.sort(friends,compareInDirection(1))
2. 修改函数的方法
public static Comparator<String> reverse(Comparator<String> comp){
return (x,y)->comp.compare(x,y);
}
它接收一个函数并返回一个修改后的函数
reverse(String::compareToIgnoreCase)//获得大小写不敏感的降序

局部内部类
public static IntSequence randomInts(int low,int high){
class RandomSequence implements IntSequence{
public int next(){return low+generator.nextInt(high-low);};
public boolean hasNext() {return true;}
}
return new RandomSequence();
};
创建局部类的好处,其一,类名称隐藏在方法范围内。其二,局部类的方法可以访问来自闭合作用域的变量,就像lambda表达式的变量。

匿名类(上面的RandomSequence只调用了一次,用来构造返回值,所以可以使用匿名类)
public static IntSequence randomInts(int low,int high){
return new IntSequence(){
public int next(){return low+generator.nextInt(high-low);};
public boolean hasNext() {return true;}
};
};

接口和lambda表达式笔记的更多相关文章

  1. 使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测

    概述 单测是提升软件质量的有力手段.然而,由于编程语言上的支持不力,以及一些不好的编程习惯,导致编写单测很困难. 最容易理解最容易编写的单测,莫过于独立函数的单测.所谓独立函数,就是只依赖于传入的参数 ...

  2. Java8新特性:Function接口和Lambda表达式参考

    Lambda基本:https://blog.csdn.net/wargon/article/details/80656575 https://www.cnblogs.com/hyyq/p/742566 ...

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

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

  4. Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法

    1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...

  5. 优雅实现INotifyPropertyChanged接口——利用Lambda表达式

    原文:优雅实现INotifyPropertyChanged接口--利用Lambda表达式 参考文章 在14年的时候,曾经读过上面的参考文章,不过当时并没有怎么理解,慢慢地也就将这篇文章忘诸脑后了. 直 ...

  6. Java函数式接口与Lambda表达式

    什么是函数式接口? 函数式接口是一种特殊的接口,接口中只有一个抽象方法. 函数式接口与Lambda表达式有什么关系? 当需要一个函数式接口的对象时,可以提供一个lambda表达式. package l ...

  7. Java函数式编程:一、函数式接口,lambda表达式和方法引用

    Java函数式编程 什么是函数式编程 通过整合现有代码来产生新的功能,而不是从零开始编写所有内容,由此我们会得到更加可靠的代码,并获得更高的效率 我们可以这样理解:面向对象编程抽象数据,函数式编程抽象 ...

  8. Java8 学习笔记--函数式接口与lambda表达式的关系

    在java中,lambda表达式与函数式接口是不可分割的,都是结合起来使用的. 对于函数式接口,我们可以理解为只有一个抽象方法的接口,除此之外它和别的接口相比并没有什么特殊的地方.为了确保函数式接口的 ...

  9. lambda表达式笔记

    前几天一位好友分享了一篇文章,其中讲到了lambda表达式,正好最近看了一些内容,就做做笔记吧... lambda表达式服务于函数式接口,如果需要一个函数式接口的对象时,就可以用lambda表达式代替 ...

随机推荐

  1. IEEP-网络实施-项目交付流程

    1.项目交付流程 1.1 定义 项目交付流程规定了对项目实施的管理和作业控制要求,保证了工程项目实施按照规定的程序进行 1.2 重要性 1.2.1提高客户满意度 1.2.2 提高工程效率,节约成本 1 ...

  2. js alert 封装 layui

    方式一: var aaa = function(){ function _alert(aa){ layer.msg(aa, { time: 2000, //2s后自动关闭 alert("最高 ...

  3. June 17th 2017 Week 24th Saturday

    Absence sharpens love, presence strengthens it. 相聚爱益切,离别情更深. There is almost no such love that can i ...

  4. 第二次Surm冲刺

    一.小组完成情况: 因为技术原因,小组部分代码还没有完成,现在已经可以实现简单的借书与还书操作. 二.个人情况 我对代码进行了测试,与大家进相关的讨论. 三.总结 这次实验的团队合作真的很重要,有许多 ...

  5. Locust性能测试3 no-web运行

    Locust也支持no-web的方式运行,直接通过控制台设置并发用户数.每秒启动用户数.持续压测时间. locust -f 脚本路径 -c 用户数 -r 每秒启动用户数 --run-time 持续压测 ...

  6. 【转】DDMS中线程状态的说明

    因为最近的工作中需要关注APP中的线程,在DDMS中可以查看某个应用的线程: 可以看到每个线程都有自己的status属性,那不同的status分别代表什么情况呢? running – executin ...

  7. 记安卓appium自动化测试实践

    一.软件安装 1. 安装node.js,安装路径D:\Program Files\nodejs\ 可以在官网下载https://nodejs.org/zh-cn/download/,版本号为node- ...

  8. 【luogu P1231 教辅的组成】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1231 对于每本书只能用一次,所以拆点再建边 #include <queue> #include ...

  9. UGUI防止点击穿透

    if (!IsPointerOverGameObject(Input.mousePosition)) { } public static bool IsPointerOverGameObject(Ve ...

  10. mysql的子查询in()操作及按指定顺序显示

    代码示例: in(逗号分隔开的值列表) 释:是否存在于值列表中 --------------------- 示例: select * from test where id in(3,1,5) orde ...