前几天阿粉还在和同事抱怨,说现在 JDK 都已经11,12了,结果自己还在用 JDK 7,于是就发生了下面一幕。
阿粉:老宫阿(宫保鸡丁),你说现在 JDK 都已经出到11了,你说对咱们是不是太不友好了,我都快学不动了。
老宫:先别说出到几了,你们现在开发用的是啥?
阿粉:我们还是用的7呀!
老宫:你竟然还在用7,那你知道什么是 Lambda 么?
阿粉:Lambda?听过,但是没用过呀,但是据说挺好用的,但是我觉得学起来好麻烦,我想静静!
老宫:你是不知道呀,JDK8 里面可不仅仅是 Lambda,还有好多新特性呢!
于是故事开始了,在老宫(宫保鸡丁)的讲述下,阿粉也不得不重视起来了,阿粉也要开始学习 JDK8 了,不然再往后,都直接被淘汰了!
1. Java8 核心新特性讲解
Java 8的核心新特性:Lambda(匿名函数)、流、默认方法。
自1998年JDK 1.0(Java 1.0)发布以来,Java已经受到了学生、项目经理和程序员等一大 批活跃用户的欢迎。你看从学生,到项目经理,到程序员,这么多的角色都对 Java 情有独钟,看来不学是真的不行了。
Java 8对硬件也有影响:平常我们用的 CPU 都是多核的——你的笔记本电脑或台式机上的处理器可能有四个 CPU 内核,甚至更多。但是,绝大多数现有的 Java 程序都只使用其中一个内核,其他三个都闲着,或只是用一小部分的处理能力来运行操作系统或杀毒程序。在Java 8之前,专家们可能会告诉你,必须利用线程才能使用多个内核。问题是,线程用 起来很难,也容易出现错误。
从 Java 的演变路径来看,它一直致力于让并发编程更容易、 出错更少。Java 1.0里有线程和锁,甚至有一个内存模型——这是当时的最佳做法,但事实证明,不具备专门知识的项目团队很难可靠地使用这些基本模型。Java 5添加了工业级 的构建模块,如线程池和并发集合。Java 7添加了分支/合并(fork/join)框架,使得并行 变得更实用,但仍然很困难。
而Java 8对并行有了一个更简单的新思路,不过你仍要遵循一些规则,这些规则阿粉会在后边给大家讲。
2. Lambda表达式
2.1 什么是Lambda表达式
阿粉在研究 Java 8的时候第一件事就是研究的 Lambda 表达式是怎么书写的。
Lambda表达式是带有参数变量的表达式,是一段可以传递的代码,可以被一次或多次执行,是一种精简的字面写法,其实就是把匿名内部类中“一定”要做的工作省略掉,然后由JVM通过推导把简化的表达式还原。
先给大家来个传统排序。
排序结果:
阿粉再来带大家来看看使用 Lambda 表达式的方式:
其实这是 Lambda 表达式的简单的使用,Lambda表达式里面还有很多应用。比如说使用 Lambda表达式来实现多线程。
public class TestClass {
public static void main(String[] args) {
new Thread(()-> {
for(int i=0;i<20;i++) {
System.out.println("阿粉最帅");
}
}).start();
}
}
其实你看到上面的 Lambda表达式 是不是感觉很简单,但是简单是简单,阿粉要问大家一个问题了?大家什么时候才适合使用 Lambda表达式呢?
2.2 什么时候使用 Lambda表达式
需要显示创建函数式接口对象的地方,都可以使用
实际上函数式接口的转换是Lambda表达式唯一能做的事情
用于替换以前广泛使用的内部匿名类,各种回调
3. 使用函数式接口
函数式接口定义且只定义了一个抽象方法。函数式接口很有用,因为抽象方法的签名可以描述Lambda表达式的签名。函数式接口的抽象方法的签名 称为函数描述符。所以为了应用不同的Lambda表达式,你需要一套能够描述常见函数描 述符的函数式接口。Java API中已经有了几个函数式接口,比如说 Comparable、Runnable和Callable。
Predicate
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for (T s : list) {
if (p.test(s)) {
results.add(s);
}
}
return results;
}
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
java.util.function.Predicate<T>
接口定义了一个名叫test的抽象方法,它接受泛 型T对象,并返回一个boolean。现在就可以直接使用了。在我们需要表示一个涉及类型T的布尔表达式时,就可以使用这个接口。
Consumer
public static <T> void forEach(List<T> list, Consumer<T> c) {
for (T i : list) {
c.accept(i);
}
}
forEach(Arrays.asList(1,2,3,4,5), (
Integer i)->System.out.println(i) ←─Lambda是Consumer中accept方法的实现 );
java.util.function.Consumer定义了一个名叫accept的抽象方法,它接受泛型T 的对象,没有返回(void)。你如果需要访问类型T的对象,并对其执行某些操作,就可以使用这个接口。比如,你可以用它来创建一个forEach方法,接受一个Integers的列 表,并对其中每个元素执行操作。在上面的代码中,你就可以使用这个forEach方法,并配合Lambda来打印列表中的所有元素。
至于剩下的 Function 阿粉就不给大家说了。
Java 8中的常用的函数式接口
今天阿粉就先给大家说这些关于 Java8 的特性,阿粉在接下来的文章中会继续讲述 Java8 的新特性呦。
推荐阅读
AndroidStudio里面竟然有程序员鼓励师?
什么是工程师文化?
2020,请对我好点!
编程·思维·职场
欢迎扫码关注