首页 > 代码库 > Java8 Lambda表达式介绍 -- 写给Guava使用者

Java8 Lambda表达式介绍 -- 写给Guava使用者

Guava

Guava是Google公司开源的一个实用工具库,对Java类库进行了多方面的增强。比如说,对函数式编程的支持,新的集合类(Multimap等),Cache支持,等等。在Java8之前,Guava和Java之间的关系,可以表示成下面这幅图:


但是随着Java8的发布,Guava和Java的关系发生了一些改变。Guava提供的很多功能,被内置在了Java8里,如下图所示:

本文举了几个例子,用代码来说明原先需要借助Guava来实现的功能,如何用Java7或Java8实现。

Joiner

Joiner用来拼接n个字符串,下面是一个例子:

    @Test
    public void joinerGuava() {
        List<String> strList = Arrays.asList("one", "two", "three", null);
        String csv = Joiner.on(",")
                .skipNulls()
                .join(strList);
        assertEquals("one,two,three", csv);
    }
在Java8里,我们可以借助Lambda表达式来做同样的事情:

    @Test
    public void joinerJava8() {
        List<String> strList = Arrays.asList("one", "two", "three", null);
        String csv = strList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.joining(","));
        assertEquals("one,two,three", csv);
    }

Ordering

Guava提供了Ordering类以方便我们创建Comparator,下面是一段示例代码:

    class Player {
        
        private String name;
        
        public String getName() {
            return name;
        }
        
    }
    public void orderingGuava() {
        // public abstract class Ordering<T> implements Comparator<T>
        Ordering<Player> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<Player, String>() {
            @Override
            public String apply(Player foo) {
                return foo.getName();
            }
        });
    }
在Java8里,我们可以这样做:

    public void comparingJava8() {
        Comparator<Player> cmp = Comparator.comparing(Player::getName,
                Comparator.nullsFirst(Comparator.naturalOrder()));
    }

Optional

Optional可以显式的指出一个引用可能是null,下面是从Guava文档里抄到的例子:

// Guava
Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
java.util.Optional可以做类似的事情,而且方法也大同小异,这里就不贴代码了。

Preconditions.checkNotNull()

如果想保证一个引用不是null(尽早抛出NullPointerException),可以像下面这样写:

    class Player {
        
        private final String name;
        
        public Player(String name) {
            this.name = Preconditions.checkNotNull(name);
        }
        
    }

checkNotNull()方法一共有三个版本:

public static <T> T checkNotNull(T reference)public static <T> T checkNotNull(T reference, Object errorMessage)public static <T> T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs)
java.util.Objects提供了三个类似的方法:

public static <T> T requireNonNull(T obj) // @since 1.7public static <T> T requireNonNull(T obj, String message) // @since 1.7public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) // @since 1.8

Guava Objects

com.google.common.base.Objects类里的一些方法,可以替换成java.util.Objects里的方法,比如:

// com.google.common.base.Objects
public static boolean equal(@Nullable Object a, @Nullable Object b)
public static int hashCode(@Nullable Object... objects)
可以用下面的方法替换:

// java.util.Objects
public static boolean equals(Object a, Object b) // @since 1.7
public static int hashCode(Object o) // @since 1.7
public static int hash(Object... values) // @since 1.7

函数式编程

很多人使用Guava的直接原因,可能就是想更好的进行函数式编程。为了支持函数式编程,Guava提供了下面这两个接口:

public interface Function<F, T> {
    @Nullable T apply(@Nullable F input);
}
public interface Predicate<T> {
    boolean apply(@Nullable T input);
}

Guava的各种集合帮助类都提供了大量使用上面两个接口的方法,比如Iterables、Collections2、Maps等等。但是Guava的函数式编程,仍然是建立在Java匿名类的语法之上,虽然一定程度上降低了代码的丑陋程度,但是仍然不够理想。Java8的出现,彻底让Guava的函数式编程变的多余。

HashMultimap

假设我们想按照玩家的groupId来给玩家分组,Java8以前,可以这样做:

    public void mapListJava7(List<Player> players) {
        Map<Integer, List<Player>> groups = new HashMap<>();
        for (Player player : players) {
            List<Player> group = groups.get(player.getGroupId());
            if (group == null) {
                group = new ArrayList<>();
                groups.put(player.getGroupId(), group);
            }
            group.add(player);
        }
    }
如果用Guava的Multimap,代码就会清晰很多:

    public void guavaMultimap(List<Player> players) {
        Multimap<Integer, Player> groups = ArrayListMultimap.create();
        for (Player player : players) {
            groups.put(player.getGroupId(), player);
        }
    }
现在,可以用Lambda表达式来更清晰的表达意图:

    public void groupingByJava8(List<Player> players) {
        Map<Integer, List<Player>> groups = players.stream()
                .collect(Collectors.groupingBy(Player::getGroupId));
    }

结论

Guava是一个很好的库,但是随着Java自身的改进,Guava的很多功能已经变得多余。




Java8 Lambda表达式介绍 -- 写给Guava使用者