java8推出了很多更新,但是在编码方面,总结起来我认为有三大块:Lambda语法,Stream包,Function包。
Lambda语法
基本语法:
(parameters) -> expression
(parameters) ->{ statements; }
假设有一个玩家List ,程序员可以使用 for 语句 ("for 循环")来遍历,在Java SE 8中可以转换为另一种形式:
// 以前的循环方式
for (String player : players) {
System.out.print(player + "; ");
}
// 使用 lambda 表达式以及函数操作(functional operation)
players.forEach((player) -> System.out.print(player + "; "));
正如您看到的,lambda表达式可以将我们的代码缩减到一行。 下面是使用lambdas 来实现 Runnable接口 的示例:
// 1.1使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
}).start();
// 1.2使用 lambda expression
new Thread(() -> System.out.println("Hello world !")).start();
// 2.1使用匿名内部类
Runnable race1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
};
// 2.2使用 lambda expression
Runnable race2 = () -> System.out.println("Hello world !");
lambda表达式可以将多行代码转换成单行语句。
Stream使用
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。
Stream提供串行(stream)和并行(parallelStream)两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。
在 Java 7 中,如果要发现 type 为 grocery 的所有交易,然后返回以交易值降序排序好的交易 ID 集合,我们需要这样写:
List < Transaction > groceryTransactions = new Arraylist < > ();
for (Transaction t: transactions) {
if (t.getType() == Transaction.GROCERY) {
groceryTransactions.add(t);
}
}
Collections.sort(groceryTransactions, new Comparator() {
public int compare(Transaction t1, Transaction t2) {
return t2.getValue().compareTo(t1.getValue());
}
});
List < Integer > transactionIds = new ArrayList < > ();
for (Transaction t: groceryTransactions) {
transactionsIds.add(t.getId());
}
而在 Java 8 使用 Stream,代码更加简洁易读;而且使用并发模式,程序执行速度更快。
List<Integer> transactionsIds = transactions.parallelStream().
filter(t -> t.getType() == Transaction.GROCERY).
sorted(comparing(Transaction::getValue).reversed()).
map(Transaction::getId).
collect(toList());
我们可以看出来,stream提供了filter、sorted、map、collect等通俗易懂的方法来解决汇聚问题来看下它的API
除了上述的几个方法外,还有limit、min、distinct等实用的方法供我们来调用。
注意:
这些方法的入参是需要一系列的比较器(Ccompare)、Boolean返回器(Predicate)、Function等工具的,这些就是下面的Function包的内容了。
再来看一个limit/skip的使用,limit 返回 Stream 的前面 n 个元素;skip 则是扔掉前 n 个元素
public void testLimitAndSkip() {
List < Person > persons = new ArrayList();
for (int i = 1; i <= 10000; i++) {
Person person = new Person(i, "name" + i);
persons.add(person);
}
List < String > personList2 = persons.stream().
map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
System.out.println(personList2);
}
private class Person {
public int no;
private String name;
public Person(int no, String name) {
this.no = no;
this.name = name;
}
public String getName() {
System.out.println(name);
return name;
}
}
输出结果
name1
name2
name3
name4
name5
name6
name7
name8
name9
name10
[name4, name5, name6, name7, name8, name9, name10]
Function包
java.util.function包下面有大量的函数式接口,主要分为以下几个基本类别
Function 输入参数为类型T, 输出为类型R, 记作 T -> R
Consumer 输入参数为类型T, 输出为void, 记作 T -> void
Supplier 没有输入参数, 输出为类型T, 记作 void -> T
Predicate 输入参数为类型T, 输出为类型boolean, 记作 T -> boolean
例如计算字符串长度的Function例子
Function<String, Integer> fc = s -> s.length();
再例如,切割字符串的Consumer
Consumer<String> consumer = c -> c.split(",");
如果输入参数是两个,这是可以使用
BiFunction<T,U,R> 记作 <T,U> -> R
BiConsumer<T,U> 记作 <T,U> -> void
BiPredicate<T,U> 记作 <T,U> -> boolean
全部的Function接口可以查看Function包下的API:
QQ图片20180329125520.png
使用forEach方法,增加java和php程序员的工资5%:
System.out.println("给程序员加薪 5% :");
Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());
javaProgrammers.forEach(giveRaise);
phpProgrammers.forEach(giveRaise);
本文只是简单介绍了基本的用法,更多的组合操作还需在实践中摸索。
网友评论