给苹果按照重量排序
Collections.sort(lists, new Comparator() {
@Override
public int compare(Apple o1, Apple o2) {
return o1.getWeight().compareTo(o2.getWeight());
}
Java8的写法
lists.sort(Comparator.comparing(Apple::getWeight));
Java8对硬件的影响
Java8之前程序都是单线程的,如果想使用多线程那么需要自行处理并发,虽然很Java提供了线程池和并发集合,但使用Java8会更容易实现多线程
并行与共享的可变数据
写代码时不能访问共享的可变数据,这些函数成为纯函数或无状态函数或无副作用函数
Stream API
Java8新的API提供了Stream,它支持许多处理数据的并行操作,从而可以避免使用synchronized
向方法传递代码技巧(方法引用,lambda表达式)
Java8之前使用匿名内部类实现行为参数化,Java8之后使用行为参数化(通过API传递代码)不需要创建匿名内部类
函数式编程
将代码传递给方法的功能,还让我们能够使用一整套新技巧
函数式编程的基石
1,没有共享的可变数据
2,将方法和函数传递给其他方法的能力
Java中的函数
程序执行期间不能传递叫二等公民(方法,类),能传递叫一等公民,java8将函数在运行时传递把他编程一等公民
//筛选一个目录中隐藏的文件
File[] hiddenFiles1 = new File(".").listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isHidden();
}
});
//java8 写法
File[] hiddenFiles2 = new File(".").listFiles(File::isHidden);
方法引用
java8使用 方法引用:: 语法(即吧这个方法最为值)
使用File::isHidden就创建了一个方法引用
lambda-匿名函数
比如(int a) -> x+1
筛选出绿色并且重量大于150克的苹果
//筛选绿色苹果
public static List filterGreenApples(List inventory){
List result = new ArrayList<>();
for (Apple apple:inventory){
if ("green".equals(apple.getColor())){
result.add(apple);
}
}
return result;
}
//筛选重量超过150克苹果
public static List filterHeavyApples(List inventory){
List result = new ArrayList<>();
for (Apple apple:inventory){
if (apple.getWeight() > 150){
result.add(apple);
}
}
return result;
}
第一版写两个方法
可以看出很多代码都是重复的,变动部分只有if判断我们可以将这部分抽取出来
public static boolean isGreenApple(Apple apple){
return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple){
return apple.getWeight() > 150;
}
public interface Predicate{
boolean test(T t);
}
static List filterApples(List inventory,Predicate p){
List result = new ArrayList<>();
for (Apple apple:inventory){
if (p.test(apple)){
result.add(apple);
}
}
return result;
}
public static void main(String[] args){
filterApples(lists,StreamTest::isGreenApple);
filterApples(lists,StreamTest::isHeavyApple);
}
第二版
我们需要把变化的部分抽取出来,然后使用函数引用将变化的部分传递到函数中,这样就可以防止代码重复
filterApples(lists,(Apple apple) -> "green".equals(apple.getColor()));
filterApples(lists,(Apple apple) -> apple.getWeight() > 150);
filterApples(lists,(Apple apple) -> apple.getWeight() < 150 || "brown".equals(apple.getColor()));
第三版
java8中我们可以直接使用lambda表达式
流
//从一个列表中筛选金额较高的交易,然后按货币分组
Map> transactionByCurrencies = new HashMap<>();
for (Transaction transaction:transactions){
if (transaction.getPrice() > 1000){
Currency currency = transaction.getCurrency();
List transactionForCurrency = transactionByCurrencies.get(currency);
if (transactionForCurrency == null){
transactionForCurrency = new ArrayList<>();
transactionByCurrencies.put(currency,transactionForCurrency);
}
transactionForCurrency.add(transaction);
}
}
之前的写法很难一眼看出这些代码是做什么的,因为有好几个嵌套的控制流指令,下面我们使用流来解决这个问题
Map> transactionByCurrencies2 =
transactions.stream()
.filter((Transaction transaction) -> transaction.getPrice() > 1000)
.collect(Collectors.groupingBy(Transaction::getCurrency));
Java8的实现非常简洁。
我们使用集合要自己去做迭代,for-each这种迭代是外部迭代,相反,有了Stream API根本就不用操心循环的事情。数据处理完全是在库里内部进行的。这种思想叫内部迭代
并且流可以更好的利用多个处理器并行处理任务
Collection是为了存储和访问数据,而Stream是对数据描述进行计算
将苹果筛选问题转化成流
顺序处理苹果筛选为题
List heavyApples = lists.stream()
.filter((Apple apple) -> apple.getWeight() > 150)
.collect(Collectors.toList());
并行处理苹果筛选问题
List heavyApple = lists.parallelStream()
.filter((Apple apple) -> apple.getWeight() > 150)
.collect(Collectors.toList());
为保证并行,函数式编程中主要的意思是,把函数作为一等值,并且含有第二层意思,即在执行元素之间无互动
接口中默认方法
一般是库设计师使用
Optional
防止出现空指针异常
Java8的新特性
函数参数化
lambda表达式,匿名参数
流
默认方法
Optional
CompletableFuture