为什么要使用java8:
Java 几个重大版本 :
Java 从 1995 年发布到现在,也走过 18 年了,个人认为,其中几个 java 版本都肩负着重大使命,影响甚远;
jdk1.0 1995 年 5 月 23 日诞生,Oak 语言改名为 Java,并提出“Write Once ,Run anywhere”;
jdk1.2 1999 年 6 月发布,将 java 划分为 J2SE,J2ME,J2EE 三大平台;
Jdk1.4 主要是性能提升,在 2000 年时候 JAVA 成为世界上最流行的电脑语言,跟这个版本离不开关系,估计国内还有大量 的 java 应用是运行在此版本上;
Jdk5 诞生于 2004 年,他的使命就是易用,加入 1. 泛型 2 自动装箱/拆箱 3 for-each 4 static import 5 变长参数等,
为了表示该版本的重要性,J2SE1.5 更名为 Java SE 5.0;
Jdk8 将在 2014 年 3 月份发布,迄今为止,可能是最大更新的 java 版本,也是令人期待的一个版本,在 Java 中引入闭包概念 对 Java 程序开发方法的影响甚至会大于 Java5 中引入的泛型特征对编程方式带来的影响。
可以看出,jdk 8 跟 jdk 5 之间,整整相差 10 年,这 10 年期间,相继发布 jdk 6、7 都是改动不大,这也说明,java 发展确 实有点缓慢了,以致曾经的跟随者.net 在某方面超越了 java,还有基于 jvm 上的动态语言崛起,比如 Groovy、Scala 等 。java8是迄今为止java历史上最大的改变。
java语言有个最大的问题:语言本身的语法像旧社会妇女的裹脚布又臭又长。java8(主要是 lambda 表达式)很好的解决了这个问题
lambda表达式
示例
示例1:比较我们想选出绿苹果的列表,或选出重量大于150克的苹果:
java7:
public class Apple {
private Integer weight = 0;
private String color = "";
}
List<Apple> inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")));
public static List<Apple> filterGreenApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
public static List<Apple> filterHeavyApples(List<Apple> inventory){
List<Apple> result = new ArrayList<>();
for (Apple apple: inventory){
if (apple.getWeight() > 150) {
result.add(apple);
}
}
return result;
}
java8:
public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
List<Apple> greenApples2 = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
List<Apple> heavyApples2 = filterApples(inventory, (Apple a) -> a.getWeight() > 150);
如果把判断语句抽成公共方法,如下:
public static boolean isGreenApple(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
return apple.getWeight() > 150;
}
List<Apple> greenApples = filterApples(inventory, FilteringApples::isGreenApple);
List<Apple> heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);
示例2:按重量从小到大排序:
java7:
实现一:
static class AppleComparator implements Comparator<Apple> {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort(new AppleComparator());
实现二:匿名类实现
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}});
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}});
java8:
inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
inventory.sort(Comparator.comparing(Apple::getWeight));
多条件排序:
inventory.sort((a1, a2) -> {
if (a1.getWeight().equals(a2.getWeight())) {
return a1.getColor().compareTo(a2.getColor());
} else {
return a1.getWeight().compareTo(a2.getWeight());
}
});
inventory.sort(Comparator.comparing(Apple::getWeight).thenComparing(Apple::getColor));
JAVA8-用lamda表达式和增强版Comparator进行排序 - CSDN博客
Lambda表达式格式
可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。这个定义够大的,让我们慢慢道来。
匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
简洁——无需像匿名类那样写很多模板代码。
Lambda表达式:包括参数列表、箭头、Lambda的主体,其中Lambda主体可以包括多行,这个时候必须用大括号把它括起来。
实现基础
默认方法
类型推断
函数式接口:
函数式接口定义且只定义了一个抽象方法。
函数式接口很有用,因为抽象方法的签名可以描述Lambda表达式的签名。函数式接口的抽象方法的签名称为函数描述符。所以为了应用不同的Lambda表达式,你需要一套能够描述常见函数描述符的函数式接口。JavaAPI中已经有了几个函数式接口:Comparable、Runnable和Callable。
Runnable r1 = () -> System.out.println(" Hello World 1"); // 使 用 Lambda
Runnable r2 = new Runnable() { // 使 用 匿 名 类
public void run() {
System.out.println(" Hello World 2");
}
};
java8在java.util.function包中引入了新的函数式接口:
Java 8 中 的 常 用 函 数 式 接 口
Lambdas 及 函 数 式 接 口 的 例 子
原始类型特化:是为了避免原始类型和引用类型之间的装箱拆箱
使用示例:
java.util.function.Function<T,R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。如果你需要定义一个Lambda,将输入对象的信息映射到输出,就可以使用这个接口(比如提取苹果的重量,或把字符串映射为它的长度)。在下面的代码中,我们向你展示如何利用它来创建一个map方法,以将一个String列表映射到包含每个String长度的Integer列表。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for (T s : list) {
result.add(f.apply(s));
}
return result;
}
// [7, 2, 6]
List<Integer> l = map(Arrays.asList(" lambdas", " in", " action"), (String s) -> s.length());
// Lambda 是 Function 接 口 的 apply 方 法 的 实 现
方法引用
Lambda的一种快捷写法,针对单一方法的Lambda的语法糖,可读性更好
方法引用.png主要分三类:
1、静态方法的方法引用:Integer::parseInt
2、实例方法的引用:String::length
3、外部对象的引用:service::getByName
第2、3的区别是,第2类是lambda参数的类是操作的类,第三种是lambda操作的类是外部已存在的类,参数只操作类的参数。
方法引用示例.png
lambda实现原理
lambda表达式里面,会把lambda表达式在本类中生成一个以lambda$+数字的方法。关键点:该方法不一定是static的方法,是static还是非static,取决于lambda表达式里面是否引用了this。这就是为什么lambda表达式里面的this指向的是本地,因为他在本类里面创建了一个方法,然后把lambda表达式里面的代码放进去。
package jdk8.lambda;
/***
* lambda表达式的this
/*
public class LambdaDemo {
private String name = "Demo";
public void test() {
// lambda实现
new Thread(() -> {
System.out.println("这里的this指向当前的ThisDemo类:" + this.name);
}).start();
}
}
javap -s -v LambdaDemo.class
javap 执行结果.jpg说说javap命令 - 每天一点 - 博客园
java8 lambda表达式原理 - CSDN博客
Java8学习笔记(4) — Lambda表达式实现方式 - CSDN博客
网友评论