JDK8新特性-lambda表达式,函数式接口

1. String.join

/**
     * Returns a new String composed of copies of the
     * {@code CharSequence elements} joined together with a copy of
     * the specified {@code delimiter}.
     *
     * <blockquote>For example,
     * <pre>{@code
     *     String message = String.join("-", "Java", "is", "cool");
     *     // message returned is: "Java-is-cool"
     * }</pre></blockquote>
     *
     * Note that if an element is null, then {@code "null"} is added.
     *
     * @param  delimiter the delimiter that separates each element
     * @param  elements the elements to join together.
     *
     * @return a new {@code String} that is composed of the {@code elements}
     *         separated by the {@code delimiter}
     *
     * @throws NullPointerException If {@code delimiter} or {@code elements}
     *         is {@code null}
     *
     * @see java.util.StringJoiner
     * @since 1.8
     */
    public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

使用了StringJoiner

/** <pre> {@code
 * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
 * String commaSeparatedNumbers = numbers.stream()
 *     .map(i -> i.toString())
 *     .collect(Collectors.joining(", "));
 * }</pre>
 *
 * @see java.util.stream.Collectors#joining(CharSequence)
 * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
 * @since  1.8
*/
public final class StringJoiner {
    private final String prefix;
    private final String delimiter;
    private final String suffix;

    /*
     * StringBuilder value -- at any time, the characters constructed from the
     * prefix, the added element separated by the delimiter, but without the
     * suffix, so that we can more easily add elements without having to jigger
     * the suffix each time.
     */
    private StringBuilder value;

    /*
     * By default, the string consisting of prefix+suffix, returned by
     * toString(), or properties of value, when no elements have yet been added,
     * i.e. when it is empty.  This may be overridden by the user to be some
     * other value including the empty String.
     */
    private String emptyValue;

是支持前后缀的StringBuilder工具类,推荐使用。

2. 接口的默认方法

public interface TestI {
    default double sqrt(int a){
        return Math.sqrt(a);
    }

    double cacl();
}

使用default关键字,有点抽象类的感觉。

3. Lambda 表达式

3.1 用法

解决匿名内部类作为方法参数的冗余写法,Java编译器可以自动推导出参数类型

在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。

Lambda 表达式不会像内部类生成一个带$的class,jd-gui已经不能反编译了。

    public void runT() {

    }

    public void test(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                runT();
            }
        }).start();

        new Thread(()-> runT()).start();
    }   }

 lambda表达式在Java编译器可以自动推导出参数类型。

 3.2 作用域

在lambda表达式中访问外层作用域和匿名内部类的访问方式很相似。可以直接访问标记了final的外层局部变量(final可省略),或者实例的字段以及静态变量。

3.2.1 访问局部变量

 

 lambda表达式访问局部变量默认就是final。

3.2.2 访问实例变量与静态变量

lambda内部对于实例变量、静态变量是可读,可写。与匿名内部类访问时一致的。

    static int num = 1;

    public static void main(String[] args) {
        Converter<Integer, String> stringConverter =
                (from) -> String.valueOf(from + num);
        System.out.println(stringConverter.apply(2));
        num = 5;
    }

3.2.3  访问接口的默认方法

lambda表达式只能覆写一个抽象方法。因此接口默认的方法无法访问。在 2. 接口的默认方法 接口的default方法,lambda表达式不能访问。

4. 函数式接口

4.1. 自定义函数式接口

函数式需要接口添加 @FunctionalInterface 注解,仅有一个抽象方法,当编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错。

@FunctionalInterface
public interface Converter<F, T> {
    //方法名自定义,因为只有一个抽象方法
    T apply(F from);
}

一个以上抽象方法报错了 

 每一个lambda表达式都对应一个类型,通常是接口类型。将lambda表达式可以映射到一个单方法的接口,lambda表达式映射的接口可以不是函数式接口

“函数式接口”是指仅仅只定义一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。

如果覆写父类的方法则可支持多个抽象方法,比如equals方法。

@FunctionalInterface
public interface Converter<F, T> {
    T apply(F from);
    boolean equals(Object obj);
}

如下示例

Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.apply("123");
System.out.println(converted);    // 123

4.2. JDK 变更或增加的函数式接口

JDK 1.8 增加的函数式接口Runnable、Comparator等,便于使用lambda表达式。

如: Comparator

/** <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <T> the type of objects that may be compared by this comparator
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see Comparable
 * @see java.io.Serializable
 * @since 1.2
 */
@FunctionalInterface
public interface Comparator<T> {
    
    int compare(T o1, T o2);

    
    boolean equals(Object obj);

    /**
     * Returns a comparator that imposes the reverse ordering of this
     * comparator.
     *
     * @return a comparator that imposes the reverse ordering of this
     *         comparator.
     * @since 1.8
     */
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

Runnable

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

 Predicate接口

/**
 * 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);

支持单参数,用于或且非比对。

        Predicate<String> predicate = (s) -> s.length() > 0;
        predicate.test("ddddd");              // true
        predicate.negate().test("ddddd");     // false

        Predicate<Boolean> nonNull = Objects::nonNull;
        Predicate<Boolean> isNull = Objects::isNull;

        Predicate<String> isEmpty = String::isEmpty;
        Predicate<String> isNotEmpty = isEmpty.negate();

 这里要注意

//isEmpty不是静态方法
Predicate<String> isEmpty = String::isEmpty;

当函数式接口的参数类型,此参数类型的类的方法调用,如上;必须直接通过类名调用的引用,否则报错,不能解析方法。

Function 接口 

@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;
    }
}

带参数和返回结果

 Supplier 接口

@FunctionalInterface
public interface Supplier<T> {

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

及其简单,只有返回结果,没有参数。

Consumer 接口 

@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); };
    }
}

只有参数,不返回。

Comparator 接口 

@FunctionalInterface
public interface Comparator<T> {
    /**
     * Compares its two arguments for order.  Returns a negative integer,
     * zero, or a positive integer as the first argument is less than, equal
     * to, or greater than the second.<p>
     *
     * In the foregoing description, the notation
     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
     * <i>expression</i> is negative, zero or positive.<p>
     *
     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
     * if <tt>compare(y, x)</tt> throws an exception.)<p>
     *
     * The implementor must also ensure that the relation is transitive:
     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
     * <tt>compare(x, z)&gt;0</tt>.<p>
     *
     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
     * <tt>z</tt>.<p>
     *
     * It is generally the case, but <i>not</i> strictly required that
     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
     * any comparator that violates this condition should clearly indicate
     * this fact.  The recommended language is "Note: this comparator
     * imposes orderings that are inconsistent with equals."
     *
     * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return a negative integer, zero, or a positive integer as the
     *         first argument is less than, equal to, or greater than the
     *         second.
     * @throws NullPointerException if an argument is null and this
     *         comparator does not permit null arguments
     * @throws ClassCastException if the arguments' types prevent them from
     *         being compared by this comparator.
     */
    int compare(T o1, T o2);

同类型比较,两个参数。返回int。

5. 方法与构造函数引用

Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用

5.1 先看方法的引用。

Converter<String, Integer> converter2 = Integer::valueOf;
Integer converted2 = converter2.apply("123");
System.out.println(converted2);   // 123

Converter<String, String> converter3 = new StringConverter() ::startWith;
String converted3 = converter3.apply("www");
System.out.println(converted3);    // "w"

可以在ide上看出

这种是lambda表达式的变种,仅一个抽象方法的lambda表达式变种,赋值是对接口做映射接口映射可以不是函数式接口,只是函数式接口仅有一个抽象方法而已,可以避免出错

void forEach(Consumer<? super T> action);

@FunctionalInterface
public interface Consumer<T> {

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


list.stream().forEach(System.out::println);

 list.stream().forEach(System.out::println);

这句代码可以直观看出方法的引用就是lambda表达式的变种,映射的接口的引用。

System.out::println映射Consumer接口,相当于lambda表达式

(s)->System.out.println(s)

5.2 构造函数引用

    @Data
    public static class Man {
        private int age;
        private String name;

        public Man(int age, String name) {
            this.age = age;
            this.name = name;
        }

    }

    Factory<Man> converter6 = Man::new;
    Man man = converter6.getFactoryBean(10, "Tom");

    //@FunctionalInterface
    public interface Factory<T> {
        T getFactoryBean(int age,String name);
    }

这里要注意,如上示例,符号 ::new 是调用构造函数Man的构造函数,接口的方法参数,必须要与构造函数的构造参数类型和个数一致

由以上示例,@FunctionalInterface仅提供强制限制一个自定义抽象方法,非强制约束,普通接口在以上示例均正常运行。

6. Optional 接口

Optional 用来防止NullPointerException异常的辅助类,在Java 8中,不推荐你返回null而是返回Optional。项目中用起来不习惯,主要用来包装可能为null的字段。

猜你喜欢

转载自blog.csdn.net/fenglllle/article/details/81978361