我的御姐儿哟,本居士当初答应你的话,现在开始履行了。
一、什么是函数式编程
函数式编程的核心思想是:思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。类似于数学中的函数求值。
我们对这种思想的完全定义还为时尚早。我们现在想要的是如何通过使用函数式编程风格的代码来写出好代码。
本系列将讲述如何实用的使用函数式编程。帮助程序媛们(恩,没打错!!!)能写出易读、易维护的代码。
下面开始进入正题。
二、Lambda表达式
2.1 在Android studio中使用Java8 的Lambda表达式的配置
首先,当然需要有1.8.0以上的jdk喽,所以别忘记了。
安装、配置1.8.0jdk
其次,对于要使用Java8 的Lambda表达式的项目,对app的bulid.gradle进行配置。
apply plugin: 'me.tatarka.retrolambda'
//设置JDK1.8
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
app的bulid.gradle相关配置
最后,对于要使用Java8 的Lambda表达式的项目,在项目的bulid.gradle的buildscript里dependencies里进行配置。
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
项目的bulid.gradle相关配置
接下来我们就可以正常的使用Java8 的Lambda表达式了。
使用Java8 的Lambda表达式
2.2 初步了解Lambda表达式
我们先来看一个简单的按钮的单击事件,为了响应用户的操作,通过注册一个事件监听器。用户一旦点击按钮,监听器就会执行相应的操作。
btn.setOnClickListener(new Button.OnClickListener(){//创建监听
public void onClick(View view) {
System.out.println("仁昌居士") ;
}
});
这个例子中,创建了一个新对象,实现了Button.OnClickListener接口。这个接口只有一个方法onClick(View v),当用户点击按钮时,按钮btn就会调用这个方法。匿名内部类实现了该方法。输出一条“仁昌居士” 的信息,表示按钮已被点击过。
使用匿名内部类就是为了方便程序媛将代码左边一个代表某种行为的对象以数据的形式进行传递。不过,一眼所见,匿名内部类太冗杂了。我有用的逻辑代码就是
System.out.println("仁昌居士") ;
但我不得不再加上一堆样板代码。
为了更简单,更容易的表达程序媛们的想法,在Java 8中,就引入了Lambda表达式,这种紧凑的、传递行为而不是对象的方式。
可将上述匿名类的使用简化为:
btn.setOnClickListener( view ->System.out.println("仁昌居士"));
分析这段代码,能发现,和传入一个实现OnClickListener接口的对象不同,我们传入的仅仅是一个函数,view是参数名,和上面匿名内部类示例中的是同一个参数。“->”就当做指示符好吧。主题是后面的用户点击button时会运行的一些代码。
我们能发现,在Lambda表达式中 view并没有像在匿名内部类里一样显式的声明参数类型 View view,这是因为,javac能够根据程序的上下文(OnClickListener方法的签名)在后台推断出参数view的类型,从而可以正常的编译。所以对于明显的参数类型不需要显示声明。**但是!**是不是就不能显式声明了呢?不,也可以显示声明的。应为,Java 8 是静态语言,编译器有时候不能根据上下文推断出参数的类型。所以该加的时候就加。对我个人而言,我还是喜欢显式声明,因为我是菜鸟嘛。
2.3 Lambda表达式的几种表现形式
Lambda表达式除了基本的形式外,还有几种不同的写法。
先上代码:
public class MainActivity extends AppCompatActivity {
private OnTestListener onTestListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(view -> System.out.println("仁昌居士"));
this.setOnTestListener(x, y -> System.out.println("仁昌居士"));
Runnable runnable = () -> System.out.println("仁昌居士");
Runnable runnable12 = () -> {
System.out.println("仁昌居士");
};
Button.OnClickListener clickListener = view -> System.out.println("仁昌居士");
BinaryOperator<Integer> integer = (x, y) -> x + y;
BinaryOperator<Integer> integer2 = (Integer x, Integer y) -> x + y;
Integer integer3 = (Integer x, Integer y) -> x + y;
}
public interface OnTestListener {
void onTestClick(int x, int y);
}
public OnTestListener getOnTestListener() {
return onTestListener;
}
public void setOnTestListener(OnTestListener onTestListener) {
this.onTestListener = onTestListener;
}
}
再截图分析:
分析形式
1和2,是为了另一个注意点,我后面会提到。
先看3,3中所示Lambda表达式实现了Runnable接口,该接口只有一个run方法,没有参数,返回类型为void ,写法上就使用"()",不包含参数。
再看4,4中所示Lambda表达式参数和3中一样,区别在于赢了“{}”,这是用于里面的代码是代码块的时候,也可以通过return和跑出异常半路退出。
接着看5,5中所示Lambda表达式仅仅只有一个参数,这个时候可以选择省略参数外的括号。
再者看6,6中所示Lambda表达式的参数是多个参数。这个时候要注意了:这行“x+y”并不是一个相加后的结果,而是一个函数操作的过程本身。
此外,可以发现6的这两个参数并没有声明类型,那是因为Lambda表达式中的参数类型都是由编译器推断得出的。虽然简单了,但是最好显示声明参数类型,如7。
接着我就要提到1,2了。看了,6,7后发现赋值的类型的是BinaryOperator<T>。我如果写成8,则会报错,查看原因,显示赋值的的类型要是个接口。
需要接口
查看BinaryOperator,能够发现他是个interface。
BinaryOperator是interface
所以回看1,2,为啥我可以这么写,因为我通过Lambda表达式得到的是个接口。
2.4 Lambda表达式引用的是值而不是变量
使用匿名内部类的时候,也许会引用他所在方法里的变量,这个时候,需要将变量声明为final。这就意味着无法再重复为其赋值,赋给该变量的是一个特定的值。
引用的变量需final
所以写法该是:
引用的变量是final
注意,引用的变量是final。有时候你不写出来也不会提示报错,是因为默认给你加了final了。
Lambda表达式中也无法用非终态变量,如果使用,编译器也会报错的。所以,Lambda表达式引用的其实是该变量第一次赋值的值,而不是变量。
Lambda表达式引用的变量同样是final
综上所述,可以对Lambda表达式有一个概念:Lambda表达式是静态类型的函数接口。
2.5 函数接口
什么是函数接口,函数接口是只有一个抽象方法的接口,用作Lambda表达式的类型。
看例子:
public interface OnTestListener {
void onTestClick(int x);
}
OnTestListener只有一个抽象方法:onTestClick(onTestClick定义在OnTestListener接口中,所以默认是抽象的,所以可以省略abstract),接受一个int 参数,并返回空。
这就是使用只有一个方法的接口来表示特定的方法并能够被反复的使用。接受的参数类型和数量,返回的类型都不重要,重要的事只有一个抽象方法。
2.6 总结
1.Lambda表达式是一个匿名的方法,传递一个代表某种行为的方式。
2.Lambda表达式有多种表现形式,常用形式:
final String name = "仁昌居士";
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(view -> System.out.println(name2+"喜欢御姐"));
参数变量的类型声明可显式可隐式。
3.Lambda表达式里引用的到的变量是final的,本质是值,不是变量。例子如上。
4.Lambda表达式的类型是个函数接口,即仅有一个抽象方法的接口。
2.7编写理由
Paste_Image.png曾答应过御姐儿要把她不懂的东西写成博客给她看,所以我就好好的写几个系列吧,此次系列JAVA8函数式编程,会写完但不定期更新。
网友评论