Java学习笔记(一)
第一次写作。这几天看了Java8实战,感觉有必要写写!Java 8 发布至今也已经好几年过去,如今Java即将迈入 Java 11,但是 Java 8 作出的改变可以说是革命性的,影响深远的,学习 Java 8 应该是 Java 开发者的必修课。
java演变
自1996年JDK(1.0)发布以来,Java已经受到了学生、项目经理和 程序员等一大批活跃的用户的欢迎。这一语言极富活力,不断被用在大大小小的项目里。从Java1.1(1997)年一直到Java7(2011)年,Java通过增加新功能,不断得到良好的升级。Java8则是在2014年3月发布的,其中带来了很多新功能,其中java函数式编程就是其中的重大变革。
什么是函数式编程
编程语言中的函数通常指的是方法 ,尤其是静态方法;这是在数学函数之外的新含义。在谈到java8的函数时,这两种用法几乎是一致的。在众多的函数式编程语言中,函数是作为一等公民(一等值),而编译语言则把方法看成二等公民。这种改变在Scala和Groovy等语言的实践以证明,让方法等概念作为一等值可以扩充程序员的工具库,从而让编程变得更容易。
java8带来的改变
java8之前java的命令式编程是很啰嗦的,例如对inventory中的苹果按照重量进行排序。
Collections.sort(inventory, new Comparator<Apple>(){
public int compare(Apple a1, Apple a2){
retuen a1.getWeight().comapreTo(a2.getWeright());
}
});
在Java8里面,你可以写出的更简洁代码,代码读起来更接近问题的描述。
inventory.sort(comparing(Apple::getWeight()));
这一行代码就把问题描述得很清晰,没有大量的模板代码,使代码更接近问题的本身。同时也大大增加了可读性和提高了编写代码的效率。你现在是不是很心动了?这只是刚刚开始而已!
下面让我们继续对比Java8究竟给我们带来了哪些改变,例如我们想筛选一个目录中的隐藏文件,需要编写如下代码
File[] files = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isHidden();
}
});
虽然只用了三行代码,但却比较的绕,不够接近问题的实质。现在Java8你可以把代码重构成下面这样:
File[] files = new File(".").listFiles(File::isHidden);
是不是很简单,在File类已有isHidden函数的条件下我们只需要用Java8的方法引用 :: 语法(即 “把这个方法作为函数参数”)就能达到我们的目的。
除了允许命名函数成为一等值以外,Java8还允许将更广义的函数作为值,包括匿名函数(lambda)。例如,你可以这样写:
(int x) -> x + 1;
调用时给定参数x,就会返回x + 1的函数值。匿名函数使函数式编程更简洁,可以不必为简单的需求而编s写一个方法。这样就很方便我们编写可读性强的代码。
下面继续看一个代码传递的例子。现在有一个筛选绿色苹果的需求,通常会写出一个filterGreenApples的方法:
public static List<Apple> filterGreenApples(List<Apple> apples) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
这些代码很简单。如果现在改一下需求,需要选出重量超过150克的苹果,甚至都不用思考,立马就可以想到filterHeavyApples方法:
public static List<Apple> filterHeavyApples(List<Apple> apples) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
你或许会复制粘贴,这两个方法除了 if 语句以外其他都是相同的。在软件工程中我们都知道重复代码是一个非常危险的信号,这个坏代码的味道会使你代码腐败的前奏。到这里你或许已经想到了利用设计模式中的模板方法解决,但是模板方法需要用多态才能完成方法重载。这在Java8以前是必须的,但是Java8以后,可以把条件代码作为参数传递进去,这就可以避免filter方法里面的重复代码,现在可以写:
public static boolean isGreenApple(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
public static List<Apple> filterApples(List<Apple> apples, Predicate<Apple> predicate) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple)) {
result.add(apple);
}
}
return result;
}
List<Apple> greenApples = filterApples(apples, FilterApples::isGreenApple);
List<Apple> heavyApples = filterApples(apples, FilterApples::isHeavyApple);
这可能已经注意到filter方法里面的参数Predicate<Apple>,这便是Java8里面新加的函数式接口。这是一个谓词,谓词(predicate)在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回true或false。Java8已经定义了Predicate函数式接口,我们现在只需要导入便可,暂时不需要考虑是如何实现的。就是这个神奇的魔法使得现在Java也可以传递代码块作为参数,这就很好的解决了重复代码的问题。
当然除了传递方法,还可以传递lambda。这样便可以不必定义那些逻辑简单且调用一两次的烦人方法而烦恼了;例如,isHeavyApple和isGreenApple这类方法,你可以这样写:
filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
filterApples(inventory, (Apple a) -> a.getWeigth() > 150);
所以,你甚至都可以不需要定义只用一次的方法;使用lambda代码更干净,更清晰。不过那些几行或者逻辑复杂的方法,你还是应该为他们定义描述性的方法名称。你的代码应该是简洁清晰的,而不是乱糟糟的。
Java8的新特性不仅仅只有这些,通过上面的陈述,也算是基本入门了Java8的函数式编程。这只是我的一点点感悟!第一次写作,受限于本人水平有限,如有不妥,还望见谅。
网友评论