深入理解Java8

Lambda的基本语法

(parm1,parm1,parm1) ->{
};

lambda表达式结构

  • 一个lambda表达式可以有零个或多个参数
  • 参数的类型既可以明确声明,也可以根据上下文来推断
  • 所有参数需包含在圆括号内,参数之间用逗号相隔
  • 空圆括号代表参数集为空
  • 当只有一个参数,且其类型可推导时,圆括号()可省略
  • Lambda表达式的主体可包含零条或多条语句
  • 如果Lambda表达式的主题只有一条语句,花括号{}可以省略。匿名函数的返回类型与该主体表达式一致
  • 如果Lambda表达式的主题包含一条以上语句,则表达式必须包含再花括号{}中。匿名函数的返回类型与代码块的返回类型一致,若没有则返回为空

函数式接口

  • 一个接口中只有一个抽象的方法
  • 声明函数式接口时,在接口上添加@FunctionalInterface注解,这样编译器会按照函数式接口去验证
  • 一个接口中只有一个抽象方法时,编译器会默认这个接口为函数式接口
  • 接口中定义的方法为定级父类Object类中的方法时,接口可以拥有两个及以上的方法。因为接口的实现类也会继承Object,所以编译器会认为接口中只有一个方法

注意点

  • 在Python、JavaScript等语言中lambda为函数,在java中lambda为对象
  • 在java8中,接口中可以有具体方法的实现,必须是default meathod
  • 在java中可以使用静态方法

函数式接口如何实例

函数式方法的声明

  1. 采用lambda表达式的方式进行声明一个接口实例
   package funcationdemo;

   import java.util.Arrays;
   import java.util.List;

   /**
    * 描述:
    * lambda表达式练习
    *
    * @author zhusy
    * @create 2020-05-11 10:05
    */
   public class Test01 {
       public static void main(String[] args) {
           List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7);
           MyInterface myInterface = i -> {
               return i;
           };
           list.forEach(i -> System.out.println(myInterface.printElement(i)));

       }
   }
   @FunctionalInterface
   interface MyInterface{
       Integer printElement(Integer i);
   }
  1. 采用方法引用的方式进行声明
   public class Test01 {
       public static void main(String[] args) {
           List<String> list2 = Arrays.asList("hello","world","hello world");
           list2.forEach(String::toUpperCase);
       }
   }
  1. 采用构造方法的方式进行声明
   package funcationdemo;

   /**
    * 描述:
    * lambda表达式练习
    *
    * @author zhusy
    * @create 2020-05-11 10:05
    */
   public class Test01 {
       public static void main(String[] args) {
           MyInterface myInterface = Person::new;
           System.out.println(myInterface.getPerson("李华"));
       }
   }

   @FunctionalInterface
   interface MyInterface {
       Person getPerson(String name);
   }

   class Person {
       private String name;

       public Person(String name) {
           this.name = name;
       }

       public String getName() {
           return name;
       }

       public void setName(String name) {
           this.name = name;
       }

       @Override
       public String toString() {
           return "Person{" +
               "name='" + name + '\'' +
               '}';
       }
   }

函数式接口四种类型

函数式接口方法参数类型返回类型作用
Consumer消费型接口void accept(T t)Tvoid对T类型的参数进行操作
Supplier供给型接口T get()T操作数据,返回T类型的结果
Function函数型接口R apply(T t)TR对T类型参数进行操作,并返回R类型的结果
Predicate 断定型接口boolean test(T t)Tboolean确定T类型参数是否满足某约束,并返回boolean值

Lambda表达式的作用

  • 传递行为,而不仅仅是值
  • 提升抽象层次
  • API重用性更好
  • 更加灵活

Function接口

函数式接口中,可以进行传值,也可以进行行为的传递,可以让方法的使用者传递方法所需要实现的行为,方法本身做更加抽象的逻辑实现

package funcationdemo;

import java.util.function.Function;

/**
 * 描述:
 * function 函数实现
 *
 * @author zhusy 2020-05-12 13:31
 *
 */
public class FunctionTest {
    public static void main(String[] args) {
        FunctionTest functionTest = new FunctionTest();
        System.out.println(functionTest.compute(3, value -> value * value));
    }

    public int compute(int a, Function<Integer, Integer> function) {
        return function.apply(a);
    }
}

BiFunction接口

package funcationdemo;

import java.util.function.BiFunction;
import java.util.function.Function;

/****************************************
 * 描述:
 * BiFunction函数接口练习
 *  Interface BiFunction<T,U,R>
 *      T - 函数的第一个参数类型
 *      U - 函数的第二个参数类型
 *      R - 函数结果的类型
 *
 *      表示接受两个参数并产生结果的函数。
 *      是Function函数有两个参数的展现方式
 *
 *
 *
 * @author zhusy 2020-05-13 14:22
 ****************************************/
public class BiFunctionTest {
    public static void main(String[] args) {
        BiFunctionTest test = new BiFunctionTest();
//        求两个数之和
        System.out.println(test.compute(3, 4, Integer::sum));

//        System.out.println(test.compute2(3, 4, Integer::sum, item -> item * item));
//        等价于
        System.out.println(test.compute2(3, 4, (num1, num2) -> num1 * num2, value -> value * value));

    }

    /**
     * public interface BiFunction<T, U, R> {
     * <p>
     * R apply(T t, U u);
     * <p>
     * <p>
     * }
     */
    public int compute(int num1, int num2, BiFunction<Integer, Integer, Integer> function) {
        return function.apply(num1, num2);
    }


    /****
     *  default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
     *         Objects.requireNonNull(after);
     *         return (T t, U u) -> after.apply(apply(t, u));
     *     }
     * @param num1 计算的值
     * @param num2 计算的值
     * @param function 需要求和函数参数(函数参数指的是需要函数执行的行为)
     * @param function2 需要返回函数参数
     * @return 计算后返回的值
     */
    public int compute2(int num1, int num2,
                        BiFunction<Integer, Integer, Integer> function,
                        Function<Integer, Integer> function2) {
        return function.andThen(function2).apply(num1, num2);
    }
}

BinaryOperator接口

package funcationdemo;

import java.util.Comparator;
import java.util.function.BinaryOperator;

/**************************************************************
 * 描述:
 *    BinaryOperator
 *    表示对同一类型的两个操作数的操作,产生与操作数相同的结果。
 *    对于操作数和结果都是相同类型的情况
 *    是BiFunction的专业化
 *
 * @author zhusy 2020-05-13 14:31
 *
 **************************************************************/
public class BinaryOperatorTest {
    public static void main(String[] args) {
        BinaryOperatorTest test = new BinaryOperatorTest();
        System.out.println(test.compute(3, 4, Integer::sum));
        System.out.println(test.minByComparator(5, 6, Comparator.comparingInt(num -> num)));
    }

    /****
     *
     * 继承 BiFunction<T,T,T> ,也拥有 apply()方法
     * 三个参数必须是同类型的
     *
     * public interface BinaryOperator<T> extends BiFunction<T,T,T> {
     *
     * }
     *
     *
     * @param num1
     * @param num2
     * @param function
     * @return
     */
    public int compute(int num1, int num2, BinaryOperator<Integer> function) {
        return function.apply(num1, num2);
    }

    /***
     *
     *     public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
     *         Objects.requireNonNull(comparator);
     *         return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
     *     }
     *
     * @param num1 比较参数1
     * @param num2 比较数字2
     * @param comparator 比较器
     * @return 返回比较的结果
     */

    public int minByComparator(int num1, int num2, Comparator<Integer> comparator) {
        return BinaryOperator.minBy(comparator).apply(num1, num2);
    }
}

Consumer接口

package funcationdemo;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

/*********************************************************
 * 描述:
 * Consumer函数
 * 表示接受单个输入参数并且不返回结果的操作
 *
 *
 * @author zhusy 2020-05-12 14:12
 ********************************************************/
public class ConsumerTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "hello world");
        list.forEach(str->{
            String strParam = str;
            Optional<String> optional = Optional.ofNullable(strParam);
            String rtn = optional.map(strParam1 -> strParam1.toUpperCase()).orElse("");
            System.out.println(rtn);
        });

    }
}

Predicate接口

结合Stream流使用

package funcationdemo;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**************************************************************
 * 描述:
 *    Predicate
 *      表示一个参数的谓词
 *
 * @author zhusy 2020-05-13 15:40
 *
 **************************************************************/
public class PredicateTest {
    public static void main(String[] args) {
        PredicateTest test = new PredicateTest();
        System.out.println(test.isTrueOfStr("hell0", str -> str.length() > 4));
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//      Predicate 接口使用
        Predicate<Integer> predicate = i -> i % 2 == 0;
//       Optional 使用的函数
        Function<Integer, Integer> function = integer -> {
            Optional<Integer> integerOptional = Optional.of(integer);
            Integer rtn = integerOptional.map(ele -> 2 * ele).get();
            return rtn;
        };
//      输出参数
        Consumer<Integer> consumer = param -> {
            Optional<Integer> integer = Optional.ofNullable(param);
            Integer rtn = integer.map(function).get();
            System.out.println(rtn);
        };
        test.conditionFilter(list, predicate, consumer);
    }

    public boolean isTrueOfStr(String str, Predicate<String> funciton) {
        return funciton.test(str);
    }

    public void conditionFilter(List<Integer> list, Predicate<Integer> predicate, Consumer<Integer> consumer) {
        list.stream().filter(predicate).forEach(consumer);
    }
}

Supplier接口

package funcationdemo;

import java.util.function.Supplier;

/**************************************************************
 * 描述:
 *    Supplier
 *    代表结果供应商,没有要求每次调用供应商时都会返回新的或不同的结果
 *    不接受参数,返回一个结果。泛型就是需要返回结果的类型
 *
 *
 * @author zhusy 2020-05-13 16:04
 *
 **************************************************************/
public class SupplierTest {
    public static void main(String[] args) {
        Supplier<String> supplier = String::new;
        String str = supplier.get();
        str = "hello world";
        System.out.println(str);
    }
}

MethodReference

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

引用静态方法:ContainingClass::staticMethodName

package methodreference;

import java.util.Arrays;
import java.util.List;

/**************************************************************
 * 描述:
 *    MethodReference
 *    方法引用
 * @author zhusy 2020-05-13 16:43
 *
 **************************************************************/
public class MethodReferenceTest {

    static void toUpperCaseByStr(String str) {
        System.out.println(str.toUpperCase());
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "hello world");
//        ContainingClass::staticMethodName 引用静态方法
        list.forEach(MethodReferenceTest::toUpperCaseByStr);
    }
}

引用某个对象的实例方法:containingObject::instanceMethodName

package methodreference;

import java.util.Arrays;
import java.util.List;

/**************************************************************
 * 描述:
 *    MethodReference
 *    方法引用
 * @author zhusy 2020-05-13 16:43
 *
 **************************************************************/
public class MethodReferenceTest {

    void toUpperCaseByStr(String str) {
        System.out.println(str.toUpperCase());
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world", "hello world");
        //      引用某个对象的实例方法
        MethodReferenceTest test = new MethodReferenceTest();
        list.forEach(test::toUpperCaseByStr);
    }
}

引用某个类型的任意对象的实例方法:ContainingType::methodName

package methodreference;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

/**************************************************************
 * 描述:
 *    MethodReference
 *    方法引用
 * @author zhusy 2020-05-13 16:43
 *
 **************************************************************/
public class MethodReferenceTest{

    public static void main(String[] args) {
        /*引用某个类型的任意对象的实例方法*/
        List<String> list = Arrays.asList("hello", "world", "hello world");
        list.sort(String::compareTo);
        list.forEach(System.out::println);
    }
}

引用构造方法:ClassName::new

package methodreference;

import java.util.function.Supplier;

/**************************************************************
 * 描述:
 *    MethodReference
 *    方法引用
 * @author zhusy 2020-05-13 16:43
 *
 **************************************************************/
public class MethodReferenceTest{

    public MethodReferenceTest() {
    }

    public String getString(Supplier<String> supplier){
        return supplier.get() +"test";
    }
    public static void main(String[] args) {
        MethodReferenceTest test = new MethodReferenceTest();
        System.out.println(test.getString(String::new));
    }
}

超类上的实例方法引用

​ **组成语法格式:super::methodName

​ 方法的名称由methodName指定,通过使用super,可以引用方法的超类版本。

​ 还可以捕获this 指针,this :: equals 等价于lambda表达式 x -> this.equals(x);

数组构造方法引用

​ **组成语法格式:TypeName[]::new

例子:

​ int[]::new 是一个含有一个参数的构造器引用,这个参数就是数组的长度。等价于lambda表达式 x -> new int[x]。

​ 假想存在一个接收int参数的数组构造方法

​ IntFunction arrayMaker =int[]::new;int[] array = arrayMaker.apply(10)// 创建数组 int[10]

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 深入理解Java8

  • Trackback 关闭
  • 评论 (1)
    • manongxiaowen
    • 2021/08/18 3:38下午

    感谢博主分享,对我很有帮助,内容写的很详细,希望博主也能出一款最近很火的国产接口工具apipost的使用教程。

return top