接口
接口是双方,即服务提供方和想让它们的对象对服务是可用的那些类,之间约定的一种机制。
声明一个接口
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. vmware克隆的linux机器网络不通

    当我使用vmware的完全克隆功能克隆出两台虚拟机之后,登录发现网络不通,仔细检查发现几个问题,由于克隆之后默认的eth0网卡在系统中会变成eth1,导致之前的eth0网卡配置信息无法加载,网络不通, ...

  2. Oracle 查看session级别信息

    1. 查看活动会话信息[sql] view plain copySELECT *    FROM V$SESSION   WHERE USERNAME IS NOT NULL     AND STAT ...

  3. March 21 2017 Week 12 Tuesday

    Sometimes ever, sometimes never. 相聚有时,后会无期. Maybe love is something we can't touch but we can feel w ...

  4. 配置环境变量时,cmd下运行java -version,报错:找不到或无法加载主类 -version

    这个方面适用于报错为:java 找不到或无法加载主类,一般是找不到类的路径,问题出在CLASSPATH环境变量上,当然这是大多数.大概率的出错点 不排除根据个人情况不况,所以想起来伟大领袖毛主席的话: ...

  5. C语言 Include指令(引用头文件)

    #include "one.h" #include "two.h" int main(int argc, const char * argv[]) { one( ...

  6. IOS 集成友盟分享

    #import <Foundation/Foundation.h> @interface UMSocialSinaHandler : NSObject +(void)openSSOWith ...

  7. Gym - 101334E 多叉树遍历

    题意:给定一个字符串,求有多少种树与之对应,对应方式是,每次遍历左节点,没有了,就回溯: 分析:d[i,j] = sum(d[i+1,k-1],d[k,j]) (str[i]==str[k]); 坑点 ...

  8. 【[ZJOI2010]网络扩容】

    题目 第一问直接板子敲上去 第二问并不明白直接在残量网络上加边的神仙做法 非常显然我们需要让流量加\(k\),那么我们就使得网络里的总流量为\(maxf+k\),\(maxf\)是第一问求出来的最大流 ...

  9. 可持久化线段树(主席树)快速简洁教程 图文并茂 保证学会。kth number例题

    如果学不会也不要打我. 假设你会线段树 开始! --- 主席树也叫可持久化线段树 顾名思义,它能够保存线段树在每个时刻的版本. 什么叫每个时刻的版本?你可能对一棵普通线段树进行各种修改,这每种样子就是 ...

  10. 安卓extends和implements

    extends是继承类 implements是实现接口