JAVA8--Lambda表达式

      JAVA8--Lambda表达式

       发现很久也没有写过博客了,也谢谢大家的关注,最近我会继续更新博客。在这段时间里面我打算继续为我的博客添加一下新的内容,包括 JAVA8的语法特性、继续完成Netty框架的介绍、JAVA多线程、docker jenkins在项目中的运用等。

       在是回归到今天的主题上面来 ,lambda表达式。其实在其他语言上面已经早早出现了lambda表达式,但是对于一些弱类型的语言来说使用lambda表达式会更加的自然一些,但是怎么说都好Java提供了lambda表达式也是方面开发人员的一个好事,我们以后可以少写太多太多的匿名内部类了。现在我们先来看看lambda表达式会简洁到怎么的一个地步:

public static final void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("TONY");
        list.add("WING");
        list.add("HE");
        list.add("YAN");
        list.add("CHAO");
        list.sort((a, b) -> b.compareTo(a));
        for (String name : list) {
            System.out.println(name);
        }

    }

我们再来对比以前原来的写法

public static final void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("TONY");
        list.add("WING");
        list.add("HE");
        list.add("YAN");
        list.add("CHAO");
        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        for (String name : list) {
            System.out.println(name);
        }
    }

通过lambda表达式去编写的确是简单轻松了许多。下来我们就来详细的讲讲lambda表达式是什么使用的,希望之后通过lambda表达式能够让我们的项目代码更加简洁易用。

一、lambda表达式的语法

lambda表达式的语法相当简单,如下面伪代码所示

1、(参数) -> 表达式代码

2、(参数) -> {表达式代码}

上面两种表达式,其实都是一样的。只不过加上{}可以写多行代码而已,为了彻底明白lambda表达式的语法我们先来举个栗子。

list.sort((String a, String b) -> b.compareTo(b));   //方式1
list.sort((a, b) -> b.compareTo(a));                 //方式2
list.sort((a, b) -> {                                //方式3
    Integer result = b.compareTo(a);
    return result;
});
list.sort((String a, String b) -> {                  //方式4
    Integer result = b.compareTo(a);
    return result;
});

首先我们可以直接定义参数的类型,当然我们可以通过JAVA的类型推断直接不写参数类型也可以。重点来了,在只有一行代码的时候,我们可以直接写上具体的有具体返回值的代码即可。如上面所示,我直接返回b.compareTo(a)就可以了,连return也不用写,当然写也是不合法的,只要加上{}写return才是合法的。

除了有返回值的,当然也有void的。我们来看看一下的栗子~

    public static final void main(String[] args) {
        Runnable runnableA = () -> System.out.print("RUN");     //方式A
        Runnable runnableB = () -> {        //方式B
            System.out.print("RUN");
        };
    }

好啦基本上明白lambda表达式的语法了,那什么时候才能使用lambda表达式呢?这个要认真介绍一下函数式接口

二、函数式接口

要使用lambda表达式,前提是方法的参数的类型声明必须是相对应的函数式接口类型。例如Runnable、Comparator等都是函数式接口。当然我们也可以定义我们的函数式接口,但是在JAVA8里面就已经添加了很多实用通用型函数式接口,当然这个也是为了JAVA8的lambda表达式去准备的。

说了那么多,那为什么Runnable和Comparator这些会是函数式接口呢,其实聪明的你相信已经猜到了,就是只有一个需要实现的接口方法的接口就是函数式接口。其实也很容易去理解,毕竟lambda表达式只能表达一个方法的实现,所以如果接口里面有多个需要实现的接口方法,这可搞不掂了。

我们试试自己定义一个函数式接口,然后通过lambda表达式进行实现试试吧····

@FunctionalInterface
public interface FilterInterface<T> {
    boolean check(T target);
}

上面就是最典型的函数式,但是@FunctionalInterface 又是什么东西呢。FunctionalInterface标明是一个函数式接口,当打上这个annotation之后会检查当前接口是否满足函数式接口的规范,作用和override一样都是用于编译检查的。所以不打@FunctionalInterface也是没有问题的,但是为了规范也为了减少出错还是打上去比较稳妥,毕竟在你重写方法的时候也会打上@Override嘛

然后我们开始试试用lambda表达式来写实现

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        names = getEnglishNames(names, (name) -> name.equals("TONY") || name.equals("WING"));
    }

    public static List<String> getEnglishNames(List<String> sources, FilterInterface<String> filter) {
        List<String> results = new ArrayList<>();
        for (String name : sources) {
            if (filter.check(name)) {
                results.add(name);
            }
        }
        return results;
    }

嗯~ 可能你看见了,我上面函数式接口用了泛型。现在对于lambda表达式已经有一个很基础的概念了,下面就介绍一下JAVA所提供的标准函数式接口,省去你定义函数式接口的麻烦。

三、使用java.util.function 提供的标准函数式接口

来来来,先来个官方的表格让大家看看 JAVA8的标准库设计大师给了我们什么好东西。

Interface Summary
InterfaceDescription
BiConsumer<T,U>

Represents an operation that accepts two input arguments and returns no result.

BiFunction<T,U,R>

Represents a function that accepts two arguments and produces a result.

BinaryOperator<T>

Represents an operation upon two operands of the same type, producing a result of the same type as the operands.

BiPredicate<T,U>

Represents a predicate (boolean-valued function) of two arguments.

BooleanSupplier

Represents a supplier of boolean-valued results.

Consumer<T>

Represents an operation that accepts a single input argument and returns no result.

DoubleBinaryOperator

Represents an operation upon two double-valued operands and producing a double-valued result.

DoubleConsumer

Represents an operation that accepts a single double-valued argument and returns no result.

DoubleFunction<R>

Represents a function that accepts a double-valued argument and produces a result.

DoublePredicate

Represents a predicate (boolean-valued function) of one double-valued argument.

DoubleSupplier

Represents a supplier of double-valued results.

DoubleToIntFunction

Represents a function that accepts a double-valued argument and produces an int-valued result.

DoubleToLongFunction

Represents a function that accepts a double-valued argument and produces a long-valued result.

DoubleUnaryOperator

Represents an operation on a single double-valued operand that produces a double-valued result.

Function<T,R>

Represents a function that accepts one argument and produces a result.

IntBinaryOperator

Represents an operation upon two int-valued operands and producing an int-valued result.

IntConsumer

Represents an operation that accepts a single int-valued argument and returns no result.

IntFunction<R>

Represents a function that accepts an int-valued argument and produces a result.

IntPredicate

Represents a predicate (boolean-valued function) of one int-valued argument.

IntSupplier

Represents a supplier of int-valued results.

IntToDoubleFunction

Represents a function that accepts an int-valued argument and produces a double-valued result.

IntToLongFunction

Represents a function that accepts an int-valued argument and produces a long-valued result.

IntUnaryOperator

Represents an operation on a single int-valued operand that produces an int-valued result.

LongBinaryOperator

Represents an operation upon two long-valued operands and producing a long-valued result.

LongConsumer

Represents an operation that accepts a single long-valued argument and returns no result.

LongFunction<R>

Represents a function that accepts a long-valued argument and produces a result.

LongPredicate

Represents a predicate (boolean-valued function) of one long-valued argument.

LongSupplier

Represents a supplier of long-valued results.

LongToDoubleFunction

Represents a function that accepts a long-valued argument and produces a double-valued result.

LongToIntFunction

Represents a function that accepts a long-valued argument and produces an int-valued result.

LongUnaryOperator

Represents an operation on a single long-valued operand that produces a long-valued result.

ObjDoubleConsumer<T>

Represents an operation that accepts an object-valued and a double-valued argument, and returns no result.

ObjIntConsumer<T>

Represents an operation that accepts an object-valued and a int-valued argument, and returns no result.

ObjLongConsumer<T>

Represents an operation that accepts an object-valued and a long-valued argument, and returns no result.

Predicate<T>

Represents a predicate (boolean-valued function) of one argument.

Supplier<T>

Represents a supplier of results.

ToDoubleBiFunction<T,U>

Represents a function that accepts two arguments and produces a double-valued result.

ToDoubleFunction<T>

Represents a function that produces a double-valued result.

ToIntBiFunction<T,U>

Represents a function that accepts two arguments and produces an int-valued result.

ToIntFunction<T>

Represents a function that produces an int-valued result.

ToLongBiFunction<T,U>

Represents a function that accepts two arguments and produces a long-valued result.

ToLongFunction<T>

Represents a function that produces a long-valued result.

UnaryOperator<T>

Represents an operation on a single operand that produces a result of the same type as its operand.

看见了吗?一大堆当然我不会一个个去说,说一些重点的,其他那些估计也少用,而且会用以下说的 其他一看就懂了。

来来来同学们划重点,其中最重要的几个接口:Predicate、Consumer、Function、Supplier

1、java.util.function.Predicate<T>

我们来看看Predicate的源码。【由于篇幅有限,我把定义了default的方法全部删掉了】

/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #test(Object)}.
 *
 * @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

}

没错这个就是跟我定义的FilterInterface<T>接口差不多,主要是用于做参数的判断。我们将之前的代码改改····

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        names = getEnglishNames(names, (name) -> name.equals("TONY") || name.equals("WING"));
    }

    //filter改成Predicate接口
    public static List<String> getEnglishNames(List<String> sources, Predicate<String> filter) {
        List<String> results = new ArrayList<>();
        for (String name : sources) {
            if (filter.test(name)) {        //check方法改成Predicate的test方法
                results.add(name);
            }
        }
        return results;
    }

这样就没有必要自己去定义一个新的函数式接口了。

2、java.util.function.Consumer<T>

老规矩看看里面的源码【由于篇幅有限,我把定义了default的方法全部删掉了】

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object)}.
 *
 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

}

嗯~!估计也不用我多说了~ 就是接受一个参数,然后做一些自定义业务,业务方法中【即自定义的lambda表达式】不返回任何值。

来个demo看看怎么用:

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        doSomethingWithNames(names, (name) -> {
            if (name.equals("TONY") || name.equals("WING")) {
                System.err.println("English name : " + name);
            } else {
                System.out.println(name);
            }
        });
    }

    public static void doSomethingWithNames(List<String> names, Consumer<String> doSomething) {
        for (String name : names) {
            doSomething.accept(name);
        }
    }

3、java.util.function.Function<T>

老规矩上源码

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

}

传入一个T类型的参数,返回一个R类型的值。貌似这个更加灵活了,再举一个栗子:

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        doSomethingWithNames(names, (name) -> {
            return name.length();
        });
    }

    public static void doSomethingWithNames(List<String> names, Function<String, Integer> doSomething) {
        for (String name : names) {
            System.out.println("result:" + doSomething.apply(name));
        }
    }

4、java.util.function.Supplier<T>

上源码

/**
 * Represents a supplier of results.
 *
 * <p>There is no requirement that a new or distinct result be returned each
 * time the supplier is invoked.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #get()}.
 *
 * @param <T> the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

这个多数用作于获得一个对象,再次举个栗子:

    public static final void main(String[] args) {
        printSomething(() -> new StringBuffer("TONY").append("&WING"));
    }

    public static void printSomething(Supplier s) {
        System.out.println(s.get().toString());
    }

 

5、各种类型的标准函数式接口

为什么有DoubleConsumer、BiConsumer<T,U>、DoubleFunction<R>、IntBinaryOperator、ToDoubleBiFunction<T,U> 等等这些标准的函数式接口呢?其实原因很简单,有些是为了使用基础类型不需要去装箱拆箱的操作【例如:DoubleFunction<R>、LongToIntFunction】,有些是为了提供多个参数【例如:BiConsumer<T,U>】。

继续看看源码就懂了

/**
 * Represents an operation that accepts two input arguments and returns no
 * result.  This is the two-arity specialization of {@link Consumer}.
 * Unlike most other functional interfaces, {@code BiConsumer} is expected
 * to operate via side-effects.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #accept(Object, Object)}.
 *
 * @param <T> the type of the first argument to the operation
 * @param <U> the type of the second argument to the operation
 *
 * @see Consumer
 * @since 1.8
 */
@FunctionalInterface
public interface BiConsumer<T, U> {

    /**
     * Performs this operation on the given arguments.
     *
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);

}
/**
 * Represents a function that accepts a long-valued argument and produces a
 * double-valued result.  This is the {@code long}-to-{@code double} primitive
 * specialization for {@link Function}.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #applyAsDouble(long)}.
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface LongToDoubleFunction {

    /**
     * Applies this function to the given argument.
     *
     * @param value the function argument
     * @return the function result
     */
    double applyAsDouble(long value);
}

是不是都清晰了?其实JAVA针对lambda表达式所设计的函数式接口,已经是足够的通用了。其实我们已经看了许多的function包里的函数式接口了,其他慢慢摸索就可以啦。但是除了这些还有其他玩法喔···· 就是我们忽略的default方法,本文后面会介绍到。

 

6、标准函数式接口复合使用

刚刚不说了遗漏了关于function包里面的函数式接口的default方法的讲解吗?现在就来说说,其实在这些接口里面有很多复合使用的方式提供给我们,我们先举例看看源码是怎么定义的

/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #test(Object)}.
 *
 * @param <T> the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ANDed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     *
     * @return a predicate that represents the logical negation of this
     * predicate
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     *
     * <p>Any exceptions thrown during evaluation of either predicate are relayed
     * to the caller; if evaluation of this predicate throws an exception, the
     * {@code other} predicate will not be evaluated.
     *
     * @param other a predicate that will be logically-ORed with this
     *              predicate
     * @return a composed predicate that represents the short-circuiting logical
     * OR of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

}

我们可以看到Predicate里面可以有 or and 等等这些default方法,所以我们可以通过这些方法进行and or的操作。看看如何去利用Predicate的or方法进行复合使用:

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        //等价于之前 (name)->name.equals("TONY") || name.equals("WING")
        Predicate<String> predicate = (name)->name.equals("TONY");
        predicate = predicate.or((name)->name.equals("WING")); 
        names = getEnglishNames(names,predicate);
        doSomethingWithNames(names, System.out::println);
    }

    //filter改成Predicate接口
    public static List<String> getEnglishNames(List<String> sources, Predicate<String> filter) {
        List<String> results = new ArrayList<>();
        for (String name : sources) {
            if (filter.test(name)) {        
                results.add(name);
            }
        }
        return results;
    }

再来看看Consumer类,里面也有个andThen的方法。

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

最后看看Function方法,Function方法也有个andThen和compose方法 具体用法其实看看代码就相当清楚了

/**
 * Represents a function that accepts one argument and produces a result.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the input to the function
 * @param <R> the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * Returns a function that always returns its input argument.
     *
     * @param <T> the type of the input and output objects to the function
     * @return a function that always returns its input argument
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

 

四、Lambda表达式异常

关于lambda表达式的异常处理,如果在函数式接口当中没有定义其抛出的异常的话lambda表达式必须try catch捕获并处理异常,不能直接抛出。例如下面这种情况就会出现编译失败

//lambda表达式
doSomethingWithNames(names, (name) -> {
    throw new Exception();
    return name.length();
});

//对应的函数式接口
@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);        //没有定义抛出的异常,所以上面的lambda表达式编译失败
}

如果我们希望lambda表达式当中不直接处理异常,我们可以在函数式接口的方法上面定义抛出的异常

@FunctionalInterface
public interface FilterInterface<T> {

    boolean check(T target) throws Exception;

}

五、方法引用

当我看完JAVA的方法引用后,我觉得虽然简短,但是看上去易读性并不高。可能是我们这些老JAVA程序员来说,以前的语法已经对于我们来说根深蒂固的原因吧。先看看什么是方法引用

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        names.sort(Comparator.comparing(String::length));
    }

是不是有点难懂,我一开始也是觉得有点难懂。什么鬼啊···· 好说说究竟是什么鬼

首先我们先看看Comparator.comparing方法里面究竟是什么东西

     /**
     * Accepts a function that extracts a {@link java.lang.Comparable
     * Comparable} sort key from a type {@code T}, and returns a {@code
     * Comparator<T>} that compares by that sort key.
     *
     * <p>The returned comparator is serializable if the specified function
     * is also serializable.
     *
     * @apiNote
     * For example, to obtain a {@code Comparator} that compares {@code
     * Person} objects by their last name,
     *
     * <pre>{@code
     *     Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
     * }</pre>
     *
     * @param  <T> the type of element to be compared
     * @param  <U> the type of the {@code Comparable} sort key
     * @param  keyExtractor the function used to extract the {@link
     *         Comparable} sort key
     * @return a comparator that compares by an extracted key
     * @throws NullPointerException if the argument is null
     * @since 1.8
     */
    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

可以看到的是里面是一个Function的参数,会通过keyExtractor获得其返回的值,然后通过这个值去进行排序。那么String::length 又代表了什么啊?事实上String::length就是Function入参的类型,然后通过类型获得其对象的方法引用。简单来说就是入参会是String类型,并且调用其对象的length方法获得值,然后在comparing方法当中获得这个值并通过compareTo方法进行对比。排序后的结果如下:

HE
YAN
TONY
WING

Process finished with exit code 0

我们再举个例子应该就懂了,打印输出一个列表:

    public static final void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("TONY");
        names.add("YAN");
        names.add("WING");
        names.add("HE");
        names.sort(Comparator.comparing(String::length));
        doSomethingWithNames(names, System.out::println);
        class Test {
            private String a;

            Test() {
                a = "ABC";
            }

            @Override
            public String toString() {
                return a;
            }
        }
        printSomething(Test::new);

    }

    public static void doSomethingWithNames(List<String> names, Consumer<String> doSomething) {
        for (String name : names) {
            doSomething.accept(name);
        }
    }

    public static void printSomething(Supplier s) {
        System.out.println(s.get().toString());
    }

给我的感觉真的是,可以啥写····· 怎么都好多联系几次基本上就明白怎么去写了。

六、总结

其实看完lambda表达式之后,感觉的确是比以前方便简洁了许多intellij IDE 针对lambda表达式也会有接口跳转。但是对于一些项目比较老旧就无法使用了,如果是作为一个产品有可能部署到一个JAVA环境版本较低的系统上使用时还说要三思而后行。不过JAVA8这次对于语法上提供很更多的支持也是一件非常好的事情,起码能够跟上时代潮流的节奏嘛···· 后面会陆陆续续添加JAVA8的新语法介绍 有兴趣的可以留意下。如果有写的不对的地方希望有评论留言给我,我会及时更正。大家也可以在评论区踊跃评论····· 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值