博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 8 基础教程(一)
阅读量:6083 次
发布时间:2019-06-20

本文共 4585 字,大约阅读时间需要 15 分钟。

  hot3.png

通过一些小代码段,看看Java8新的特性吧

接口的默认方法 Default Methods for Interfaces:

Java8允许我们使用default 关键字来实现对非抽象方法的实现,例:

interface Formula {double calculate(int a);default double sqrt(int a) { return Math.sqrt(a);}}

看,Formula定义了一个抽象方法calculate,然后又定义了一个默认方法sqrt,具体的类只要实现抽象方法calculate即可,默认方法可以直接使用。

Formula formula = new Formula() {@Overridepublic double calculate(int a) { return sqrt(a * 100);}};

formula.calculate(100); // 100.0 formula.sqrt(16); // 4.0

上面的这段代码中,formula是通过匿名对象实现的。当然,这段代码看起来过于繁琐,用6行代码实现一个小小的计算sqrt(a * 100),不过在下面我们会看到Java8用更加帅气的方式实现单个方法对象的做法,那就是

Lambda 表达式

让我们先来一个小例子:看看在之前的Java版本中如何实现对String字符串进行排序

List
names = Arrays.asList("peter", "anna", "mike", "xenia");Collections.sort(names, new Comparator
() {@Overridepublic int compare(String a, String b) { return b.compareTo(a);} });

Collections.sort这个方法的参数是一个列表和一个比较器,它可以对你给出的list进行排序。这样你就发现经常需要创造一些匿名的comparators来进行排序方法。

为了取代一直以来的创造匿名对象的方式,Java8推出了更加简洁的语法:lambda表达式:

Collections.sort(names, (String a, String b) -> {return b.compareTo(a); });

就像你看见的这段代码,它,更加的简洁,更加的清晰易读,但是,它还可以更加的简洁:

Collections.sort(names, (String a, String b) -> b.compareTo(a));

这行代码,你可以省略掉{}和关键字return,但是还可以更简洁:

Collections.sort(names, (a, b) -> b.compareTo(a));

Java编译器可以自动判断参数类型,因此,类型也可以省略

感受到了简洁的语法后,我们需要深入了解一下,看看Lambda表达式怎样在实际工作中使用:

函数式接口

Lambda表达式是怎样匹配Java类型系统呢?通过接口指定,每一个lambda对应一个给定的类型。一个被称为函数式接口必须要包含一个准确的抽象方法的声明。这样每个lambda和它的对应类型将会匹配到个抽象方法。因为default method不是抽象的,所以可以自由的在函数式接口中添加default方法 只要这个接口包含唯一的一个抽象方法,我们就可以使用任意的接口。为了确定你的接口满足要求,需要添加一个@FunctionalInterface注解,这样,当你试图给这个接口添加第二个抽象方法声明的时候,编译器就会自动感知,会抛出一个编译期错误。

栗子: <!-- lang:java --> @FunctionalInterface interface Converter<F, T> { T convert(F from); } <!-- lang:java --> Converter<String, Integer> converter = (from) -> Integer.valueOf(from); Integer converted = converter.convert("123"); System.out.println(converted); // 123

记住:如果代码中没有写注解 @FunctionalInterface,那么也是错误的!

方法和构造函数的引用

上面实例的代码通过使用静态函数引用可以进一步的简化

Converter
converter = Integer::valueOf; Integer converted = converter.convert("123"); System.out.println(converted); // 123

Java 8 允许你使用关键字 :: 来引用方法和构造器。上面的代码显示的是怎样引用一一个静态方法。但是我们同样,也可以引用对象方法。 <!-- lang:java --> class Something { String startsWith(String s) { return String.valueOf(s.charAt(0)); } }

Something something = new Something();    Converter
converter = something::startsWith; String converted = converter.convert("Java"); System.out.println(converted); // "J"

让我们看看 :: 关键字对于构造方法是如何工作的。首先我们需要构造一个带有不同构造器的bean实例: <!-- lang:java --> class Person { String firstName; String lastName;

Person() {}            Person(String firstName, String lastName) {            this.firstName = firstName;            this.lastName = lastName;        }    }

然后我们来指定一个person 工厂接口,为创建person对象时使用: <!-- lang:java --> interface PersonFactory<P extends Person> { P create(String firstName, String lastName); } 我们可以通过构造器引用来连接所有的东西,来取代手动的创建工厂 <!-- lang:java --> PersonFactory<Person> personFactory = Person::new; Person person = personFactory.create("Peter", "Parker"); 我们通过Person::new 创建了一个Person构造器的引用,Java编译器会通过PersonFactory.create的方法签名,匹配到正确的构造器方法。

Lambda作用域

从Lambda表达式中获取外部作用域变量的方式与匿名对象的方式非常相似,你可以获取final变量从局部外部变量中,跟实例域和静态变量一样。 获取局部变量 我们可以读取final局部变量从lambda表达式的外部作用域中 <!-- lang:java --> final int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

但是不同于匿名对象,变量num不需要必须设置为final,下面的代码同样有效: <!-- lang:java --> int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

然而,num是一个隐式的final局部变量,编译器才能通过。下面这段代码就不会编译通过: <!-- lang:java --> int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); num = 3; 在Lambda表达式内部修改num的值同样是不被允许的。你只要把这个变量看做final修饰的即可,只是final没有写出来罢了。

获取实体域和静态变量 不同于局部变量,我们在具有Lambda表达式的代码中,可以对实体域和静态变量进行读和写的权利。这种方式同样在匿名对象中为我们所熟知。 <!-- lang:java --> class Lambda4 { static int outerStaticNum; int outerNum;

void testScopes() {            Converter
stringConverter1 = (from) -> { outerNum = 23; return String.valueOf(from); }; Converter
stringConverter2 = (from) -> { outerStaticNum = 72; return String.valueOf(from); }; } }

获取默认接口方法: 还记得开头讲述的formula 那个栗子吗?接口fomula定义个一个默认方法:sqrt,可以被包含匿名对象的每一个formula实例使用,这种机制跟lambda表达式无关

默认方法不能被lambda表达式使用,下面的代码不能被编译: <!-- lang:java --> Formula formula = (a) -> sqrt( a * 100);

转载于:https://my.oschina.net/sudojs/blog/209691

你可能感兴趣的文章
Windows Azure 保留已存在的虚拟网络外网IP(云服务)
查看>>
修改字符集
查看>>
HackTheGame 攻略 - 第四关
查看>>
js删除数组元素
查看>>
带空格文件名的处理(find xargs grep ..etc)
查看>>
华为Access、Hybrid和Trunk的区别和设置
查看>>
centos使用docker下安装mysql并配置、nginx
查看>>
关于HTML5的理解
查看>>
需要学的东西
查看>>
Internet Message Access Protocol --- IMAP协议
查看>>
Linux 获取文件夹下的所有文件
查看>>
对 Sea.js 进行配置(一) seajs.config
查看>>
第六周
查看>>
解释一下 P/NP/NP-Complete/NP-Hard 等问题
查看>>
javafx for android or ios ?
查看>>
微软职位内部推荐-Senior Software Engineer II-Sharepoint
查看>>
sql 字符串操作
查看>>
【转】Android布局优化之ViewStub
查看>>
网络安全管理技术作业-SNMP实验报告
查看>>
根据Uri获取文件的绝对路径
查看>>