接口
接口是双方,即服务提供方和想让它们的对象对服务是可用的那些类,之间约定的一种机制。
声明一个接口
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. JS检查输入项是否为手机号码或者固话号码的正则表达式

    var reg = /^((0\d{2,3}-\d{7,8})|(1[34578]\d{9}))$/; //校验手机号和固定电话 if ( !reg.test(shop_tel) || check_e ...

  2. python编写脚本,删除固定用户下的所有表

    脚本如下: [oracle@ycr python]$ more t_del.py #/usr/bin/python#coding:utf8 import sysimport cx_Oracle i=0 ...

  3. 元素float以后,div高度无法自适应解决方案

    首先要明白 >> 浮动的子元素会脱离文档流,不再占据父元素的空间,父元素也就没有了高度. 解决方案:1 给父元素加上overflow:hidden;属性就行了. 第一种:(给父级加over ...

  4. POJ-1080 Human Gene Functions---类似LCS

    题目链接: https://cn.vjudge.net/problem/POJ-1080 题目大意: 给定两组序列,要你求出它们的最大相似度,每个字母与其他字母或自身和空格对应都有一个打分,求在这两个 ...

  5. SQL SERVER启动时间

    select sqlserver_start_time,* from sys.dm_os_sys_info

  6. 【LOJ6062】「2017 山东一轮集训 Day2」Pair(线段树套路题)

    点此看题面 大致题意: 给出一个长度为\(n\)的数列\(a\)和一个长度为\(m\)的数列\(b\),求\(a\)有多少个长度为\(m\)的子串与\(b\)匹配.数列匹配指存在一种方案使两个数列中的 ...

  7. java中equals以及==的用法(简单介绍)

    简单介绍 equals方法是java.lang.Object类的方法 有两种用法说明: 一.对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同. 1.“==”比较两 ...

  8. 【洛谷P2577】[ZJOI2005]午餐

    午餐 题目链接 DP题都辣么毒瘤的么.. 首先,看一下题解 我们就有了思路: 贪心:显然,让吃饭慢的先打饭,sort一遍(证明?不存在的.. DP:f[i][j][k]表示前i个人,窗口1的打饭时间为 ...

  9. Angularjs实例应用

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  10. python 实现远程上传文件夹

    python2 upload.py "ip" "root" "password" "22" "Only Pro ...