Java8-02-笔记

函数式接口

1、基本定义

  • 只包含一个抽象方法的接口,称为函数式接口。
  • 可以在任意函数式接口上使用@FunctionalInterface注解,检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
  • Java8内置的四大核心函数式接口
    • Consumer<T> :消费型接口 void accept(T t);
    • Supplier<T> :供给型接口 T get();
    • Function<T,R> :函数型接口 R apply(T t);
    • Predicate<T> :断言型接口 boolean test(T t);
  • Lambda表达式需要函数式接口的支持
    • 大家在学习函数式接口的时候注意找出Lambda使用三要素,【@111@、@222@、@333@】,就会发现要素一就是函数式接口。
    • 在学习Lambda表达式时,函数式接口是我们自己创建的,但是实际的使用过程中我们是使用Java8内置的函数式接口,不需要自己创建。

2、消费型接口

 Consumer<T>
package java.util.function;

import java.util.Objects;

/**
 * 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> {			

    void accept(T t);			//@111@
    
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
  • 案例演示
    package com.sunstone.functionalinterface;
    
    import org.junit.Test;
    
    import java.util.function.Consumer;
    
    public class TestFunctionalInterface {
    
        public void happy(double money, Consumer<Double> consumer){
            consumer.accept(money);				//@222@
        }
    
        @Test
        public void test1(){
            happy(10000, m -> System.out.println("大宝剑,每次消费: "+m+"$"));	//@333@
        }
    }
    

3、供给型接口

Supplier<T>
package java.util.function;

/**
 * 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> {

    T get();			//@111@
}
  • 案例演示
    package com.sunstone.functionalinterface;
    
    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Supplier;
    
    public class TestFunctionalInterface {
     
        //产生指定num个数的,根据传递的supplier生成随机数集合
        public List getNumList(int num, Supplier supplier){
            List list = new ArrayList();
            for (int i=0; i<num; i++){
                list.add(supplier.get());			//@222@
            }
            return list;
        }
    
        @Test
        public void test2(){
            List numList = getNumList(10, () -> (int)(Math.random()*100));	//@333@
            for(Object num: numList){
                System.out.println(num);
            };
        }
    }
    

4、函数型接口

Function<TR>
package java.util.function;

import java.util.Objects;

/**
 * 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> {

    R apply(T t);				//@111@

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  • 案例演示

    package com.sunstone.functionalinterface;
    
    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Function;
    
    public class TestFunctionalInterface {
    
        //根据传递的function对象的apply()方法来对字符串str进行处理并返回
        //该案例和之前在lambda笔记中最后的案例一样,
        	//只不过此时我们使用的不是自己定义的函数式接口MyFunction,
        	//而是使用Java8内置的函数式接口Function<T, R>
        public String strHandler(String str, Function<String, String> fun){
            return fun.apply(str);			//@222@
        }
    
        @Test
        public void test3(){
            String subStr = strHandler("孙思东0雪豹", str -> str.substring(2,5));	//@333@
            System.out.println(subStr);
        }
    }
    

5、断言型接口

Predicate<T>
package java.util.function;

import java.util.Objects;

/**
 * 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> {

    boolean test(T t);				//@111@

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

  • 案例演示

    package com.sunstone.functionalinterface;
    
    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class TestFunctionalInterface {
    
        //将满足predicate判断条件的字符串,存放到集合并返回
        public List<String> filterStr(List<String> list, Predicate<String> predicate){
            List<String> strList = new ArrayList<>();
            for (String str:list){
                if(predicate.test(str)){			//@222@
                    strList.add(str);
                }
            }
            return strList;
        }
    
        @Test
        public void test4(){
            List<String> list = Arrays.asList("bu","zhidao","fang","xiang","duibudui");
            List<String> strList = filterStr(list, s -> s.length()>3);		//@333@
            for(String str : strList){
                System.out.println(str);
            }
        }
    }
    

6、函数式接口Comparator的疑惑

package java.util;

import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;

/**
 * @since 1.2
 */
@FunctionalInterface
public interface Comparator<T> {
    
        int compare(T o1, T o2);

    /**
     * Indicates whether some other object is &quot;equal to&quot; this
     * comparator.  This method must obey the general contract of
     * {@link Object#equals(Object)}.  Additionally, this method can return
     * <tt>true</tt> <i>only</i> if the specified object is also a comparator
     * and it imposes the same ordering as this comparator.  Thus,
     * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
     * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
     * <tt>o1</tt> and <tt>o2</tt>.<p>
     *
     * Note that it is <i>always</i> safe <i>not</i> to override
     * <tt>Object.equals(Object)</tt>.  However, overriding this method may,
     * in some cases, improve performance by allowing programs to determine
     * that two distinct comparators impose the same order.
     *
     * @param   obj   the reference object with which to compare.
     * @return  <code>true</code> only if the specified object is also
     *          a comparator and it imposes the same ordering as this
     *          comparator.
     * @see Object#equals(Object)
     * @see Object#hashCode()
     */
    boolean equals(Object obj);

    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
    
    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }
    
    //多个默认方法和静态方法。。。略
}
  • 之前学习的这些个函数型接口都是只有一个抽象方法,但是comparator也是函数型接口但是却有两个抽象方法compare和equals!!!

  • 查到的一些函数性接口更准确的资料:

    • 接口有且仅有一个抽象方法,如抽象方法compare
    • 允许定义静态非抽象方法
    • 允许定义默认defalut非抽象方法(default方法也是java8才有的)
    • 允许java.lang.Object中的public方法,如抽象方法equals。
    • FunctionInterface注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上@FunctionInterface,那么编译器会报错。
  • 函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object的public方法一样
    接口最终有确定的类实现, 而类的最终父类是Object。 因此函数式接口可以定义Object的public方法。

  • If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface’s abstract method count
    since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.
    如果一个接口声明一个抽象方法来重写java.lang.object的一个公共方法,那么该方法也不计入接口的抽象方法计数。
    因为接口的任何实现都将具有java.lang.object或其他地方的实现。

  • 既然Object类里有了的方法,为什么在接口里还要定义抽象方法?
    方便要求实现类中实现方法的复写,定义自己指定的toString(),equals(),hashcode()方法。

  • Note that it is always safe not to override Object.equals(Object). However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct comparators impose the same order.
    请注意,不重写object.equals(object)始终是安全的。但是,在某些情况下,重写此方法可能会通过允许程序确定两个不同的比较器使用相同的顺序来提高性能。

  • 首先,为什么说不重写equals总是安全的。因为java中很多Collection你在取值时,实际是通过hashCode()来实现的。如果你重写了object的equals方法,可能意味着原来不相等的两个值现在奇怪的相等了,或是两个原来相等的值现在相等了。由此可能造成你原来存进去的值现在没法取出来。再者,为什么Comparator也有一个equals方法。接口是并不继承Object类的。这个方法用来比较其他对象是否等于这个比较器。当指定的对象也是一个比较器,并且和这个Comparator执行相同的顺序时,该方法返回true.

  • 为什么Comparator也有一个equals方法。接口是并不继承Object类的。这个方法用来比较其他对象是否等于这个比较器。当指定的对象也是一个比较器,并且和这个Comparator执行相同的顺序时,该方法返回true.”

  • 实际上我的问题就在这,接口虽然不是继承Object类,但实现接口的类肯定是继承Object的,那么这个类就会有equals()方法了。如果需要重写,就重写;不需要,可以不用管。 所以我不知道到底这个接口里定义的这个equals()有什么用?或者说,明明是已经有了的方法,为什么还要重复定义?

  • 上面资料里已经说了,接口里的equals方法是比较两个比较器是否相等的。而重写Object的equals方法是比较此对象与另一个OBJ是否相等的。

  • 注意,不去重写Object的equals方法总是安全的。但是,重写这个方法也许,在某些情况下,(有助于)提高效率,——因为这就允许程序作出这样的判断:两个不同的Comparator实现导致的排序结果其实是相同的。(比如两个Comparator分别对同一个巨大的集合排序,你要想知道结果是不是相同,就可以通过两个 Comparator 的 equals 结果知道,而不用去比较两个巨大的结果集合了)接口里面写上这个方法,我猜就是为了能有一个合适的地方写下这段注释,提醒程序员注意到这种对Comparator实现重写equals的可能性。当然,根据Object类里的equals协议,如果重写equals那就是说hashCode也要同时重写,这个还是要遵守的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值