Java 8 简化代码(1)

Lambda 表达式

Lambda 表达式的初衷是,进一步简化匿名类的语法

//匿名类
new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("hello1");
    }
}).start();
//Lambda表达式
new Thread(() -> System.out.println("hello2")).start();

使用 Java 8 简化代码

  • 使用 Stream 简化集合操作;
  • 使用 Optional 简化判空逻辑;
  • JDK8 结合 Lambda 和 Stream 对各种类的增强。

使用 Stream 简化集合操作

Lambda 表达式可以帮我们用简短的代码实现方法的定义,给了我们复用代码的更多可能性。利用这个特性,我们可以把集合的投影、转换、过滤等操作抽象成通用的接口,然后通过 Lambda 表达式传入其具体实现,这也就是 Stream 操作。

我们看一个具体的例子。这里有一段 20 行左右的代码,实现了如下的逻辑:

  • 把整数列表转换为 Point2D 列表;
  • 遍历 Point2D 列表过滤出 Y 轴 >1 的对象;
  • 计算 Point2D 点到原点的距离;
  • 累加所有计算出的距离,并计算距离的平均值。
private static double calc(List ints) {
    //临时中间集合
    List point2DList = new ArrayList<>();
    for (Integer i : ints) {
        point2DList.add(new Point2D.Double((double) i % 3, (double) i / 3));
    }
    //临时变量,纯粹是为了获得最后结果需要的中间变量
    double total = 0;
    int count = 0;

    for (Point2D point2D : point2DList) {
        //过滤
        if (point2D.getY() > 1) {
            //算距离
            double distance = point2D.distance(0, 0);
            total += distance;
            count++;
        }
    }
    //注意count可能为0的可能
    return count >0 ? total / count : 0;
}

现在,我们可以使用 Stream 配合 Lambda 表达式来简化这段代码。简化后一行代码就可以实现这样的逻辑,更重要的是代码可读性更强了,通过方法名就可以知晓大概是在做什么事情。比如:

  • map 方法传入的是一个 Function,可以实现对象转换;
  • filter 方法传入一个 Predicate,实现对象的布尔判断,只保留返回 true 的数据;
  • mapToDouble 用于把对象转换为 double;
  • 通过 average 方法返回一个 OptionalDouble,代表可能包含值也可能不包含值的可空 double。

下面的第三行代码,就实现了上面方法的所有工作:

List ints = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
double average = calc(ints);
double streamResult = ints.stream()
        .map(i -> new Point2D.Double((double) i % 3, (double) i / 3))
        .filter(point -> point.getY() > 1)
        .mapToDouble(point -> point.distance(0, 0))
        .average()
        .orElse(0);

Java 8 类对于函数式 API 的增强

要通过 HashMap 实现一个缓存的操作,在 Java 8 之前我们可能会写出这样的 getProductAndCache 方法:先判断缓存中是否有值;如果没有值,就从数据库搜索取值;最后,把数据加入缓存。

private Map cache = new ConcurrentHashMap<>();

private Product getProductAndCache(Long id) {
    Product product = null;
    //Key存在,返回Value
    if (cache.containsKey(id)) {
        product = cache.get(id);
    } else {
        //不存在,则获取Value
        //需要遍历数据源查询获得Product
        for (Product p : Product.getData()) {
            if (p.getId().equals(id)) {
                product = p;
                break;
            }
        }
        //加入ConcurrentHashMap
        if (product != null)
            cache.put(id, product);
    }
    return product;
}

而在 Java 8 中,我们利用 ConcurrentHashMap 的 computeIfAbsent 方法,用一行代码就可以实现这样的繁琐操作:

private Product getProductAndCacheCool(Long id) {
    return cache.computeIfAbsent(id, i -> //当Key不存在的时候提供一个Function来代表根据Key获取Value的过程
            Product.getData().stream()
                    .filter(p -> p.getId().equals(i)) //过滤
                    .findFirst() //找第一个,得到Optional
                    .orElse(null)); //如果找不到Product,则使用null
    }
}

computeIfAbsent 方法在逻辑上相当于:

if (map.get(key) == null) {
  V newValue = mappingFunction.apply(key);
  if (newValue != null)
    map.put(key, newValue);
}

你可能感兴趣的:(windows)