Java8特性

1.lambda表达式:

加入lambda之后,很多写法都变得简单起来,如创建一个线程对象

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.print("Hello");
    }
});

lambda写法:
new Thread(() -> System.out.print("Hello"));

单独将lambda拎出来:
Runnable runnable = () -> System.out.print("Hello");

其实lambda代表的就是一个接口的实现而已(匿名内部类)。
而这种接口也叫函数式接口,会有@FunctionalInterface注解进行编译时检查。
或者直接把lambda看成一个方法,上述的 () -> System.out.print("Hello") 就是代表一个无入参、无返回值的一个方法(等同于public void run() {System.out.print("Hello")}),而Runnable runnable则是指向这个方法(类似函数指针),需要调用这个方法时,调用runnable.run()即可.

当有一个参数、无返回值则是Consumer<T>
// 对printStream对象的void print(String s)方法的引用
PrintStream printStream = System.out;
Consumer<String> consumer = printStream::print;
consumer.accept("Hello");
// 输出
Hello

在这里插入图片描述

以上为java.util.function包下的部分接口,剩余的基本上就是指定泛型类型的函数接口了,例如LongConsumer,无泛型,其实就是指定入参只能是Long。

上述已经代表了大部分的函数可以表示的形式了(值得注意的是,三个及以上的入参的函数式接口JDK并没有提供,需要时要自定义实现,实际上也很少用到)。

方法有静态方法(static)和非静态方法,但函数式接口关注的仅是入参、出参类型和个数而已:
public Class Test {
    public Long noStaticFoo(String str) {...}
    public static Long staticFoo(String str) {...}
    
    public static void main() {
        // 静态方法,类::
        Function<String, Long> staticFoo = Test::staticFoo;
        Long apply = staticFoo.apply("100");
        
        // 非静态方法,实例对象::
        Test test = new Test();
        Function<String, Long> noStaticFoo = test::noStaticFoo;
        Long apply2 = noStaticFoo.apply("100");
        
        /* 这种可以理解成两个入参、除了原来方法的入参外,还要指明实例对象(因为这是一个实例方法)*/
        BiFunction<Test, String, Long> noStaticFooTest = Test::noStaticFoo;
        Long apply3 = noStaticFooTest.apply(test, "100");
    }
}

java8异步方法调用写法

  public class UserHttpService {
        public User getById(Long id) {
            ...
            return user;
        }
    }
public class AsyncExecutor {
        // 线程池,建议恰当配置(拒绝策略建议CallerRunsPolicy)和使用框架注入
        private ExecutorService executorService = Executors.newFixedThreadPool(10);

        /**
        * 单个入参,有返回值的异步执行方法 , public User getById(Long id)
        *
        * @param method 要执行的方法,如 , userHttpService::getById
        * @param param  入参值,如 100
        * @param <P>    入参类型,如 Long
        * @param <R>    返回值类型,如 User
        * @return Future对象,用以判断是否执行结束、获取返回结果
        */
        public <P, R> Future<R> async(Function<P, R> method, P param) {
            return executorService.submit(() -> method.apply(param));
        }
    }
public class A {

    private AsyncExecutor asyncExecutor;

    private UserHttpService userHttpService;

    public void foo() {
      ...
      // 异步调用
      Future<User> userFuture = asyncExecutor.async(userHttpService::getById, id);

      ... 其他操作(如再发起http请求)
 
      // 获取结果
      User user = userFuture.get();
      ...
    }
}
public class AsyncExecutor {
      // 线程池,建议恰当配置(拒绝策略建议CallerRunsPolicy)和使用框架注入
      private ExecutorService executorService = Executors.newFixedThreadPool(10);
     
     /**
     * 无入参,无返回值的异步执行方法 , void noStaticFoo()
     *
     * @param method 要执行的方法,如 user::noStaticFoo;
     * @return Future对象,用以判断是否执行结束
     */
    public Future async(Runnable method) {
        return executorService.submit(method);
    }

    /**
     * 有单个入参,无返回值的异步执行方法,如 void noStaticFoo(Long id)
     *
     * @param method 要执行的方法,如, user::noStaticFoo
     * @param param  方法执行的入参,如id
     * @param <P>    入参类型,如Long
     * @return Future对象,用以判断是否执行结束
     */
    public <P> Future async(Consumer<P> method, P param) {
        return executorService.submit(() -> method.accept(param));
    }

    /**
     * 有两个参数但是无返回值的异步执行方法, 如void noStaticFoo(Long id,Entity entity)
     *
     * @param method 要执行的方法,如 , user::noStaticFoo
     * @param param1 第一个入参值,如id
     * @param param2 二个入参值,如entity
     * @param <P1>   第一个入参类型
     * @param <P2>   第二个入参类型
     * @return Future对象,用以判断是否执行结束
     */
    public <P1, P2> Future async(BiConsumer<P1, P2> method, P1 param1, P2 param2) {
        return executorService.submit(() -> method.accept(param1, param2));
    }

    /**
     * 无参数有返回值的异步执行方法 , Entity noStaticFoo()
     *
     * @param method 要执行的方法,如 , user::noStaticFoo
     * @param <R>    返回值类型,如 Entity
     * @return Future对象,用以判断是否执行结束、获取返回结果
     */
    public <R> Future<R> async(Supplier<R> method) {
        return executorService.submit(method::get);
    }

    /**
     * 单个入参,有返回值的异步执行方法 , Entity noStaticFoo(Long id)
     *
     * @param method 要执行的方法,如 , user::noStaticFoo
     * @param param  入参值,如 id
     * @param <P>    入参类型,如Long
     * @param <R>    返回值类型,如 Entity
     * @return Future对象,用以判断是否执行结束、获取返回结果
     */
    public <P, R> Future<R> async(Function<P, R> method, P param) {
        return executorService.submit(() -> method.apply(param));
    }

    /**
     * 两个入参,有返回值的异步执行方法 , Entity noStaticFoo(Long id)
     *
     * @param method 要执行的方法,如 , user::noStaticFoo
     * @param param1 第一个入参值,如id
     * @param param2 二个入参值,如entity
     * @param <P1>   第一个入参类型
     * @param <P2>   第二个入参类型
     * @param <R>    返回值类型,如 Entity
     * @return Future对象,用以判断是否执行结束、获取返回结果
     */
    public <P1, P2, R> Future<R> async(BiFunction<P1, P2, R> method, P1 param1, P2 param2) {
        return executorService.submit(() -> method.apply(param1, param2));
    }
}
JDK1.8 有提供CompletableFuture,也是类似异步处理的方法,默认线程池为ForkJoinPool(默认最大工作线程数=CPU总核心数-1),该线程池擅长于计算密集型任务,IO密集型任务请尽量使用自己合理配置的线程池。

函数式接口

函数式接口就是只定义一个抽象方法的接口.例如:Comparator和Runnable 和 Predicate  和 FileFilter
接口现在还可以拥有默认方法(即在类没有对方法进行实现时, 其主体为方法提供默认实现的方法)。
哪怕有很多默认方法,只要接口只定义了一个抽象 方法,它就仍然是一个函数式接口。

注意(函数式接口):
函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object的public方法一样
接口最终有确定的类实现, 而类的最终父类是Object。Comparator有两个抽象方法(compare和equals方法)  ,Comparator类的equals方法名和Object的equals方法一样.
所有类默认继承Object,所以该类已有了Object的equals方法,相当于重写了equals方法。

在这里插入图片描述

用函数式接口可以干什么呢?
Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例(具体说来,是函数式接口一个具体实现 的实例)。
你用匿名内部类也可以完成同样的事情,只不过比较笨拙:需要提供一个实现,然后 再直接内联将它实例化。
下面的代码是有效的,因为Runnable是一个只定义了一个抽象方法run 的函数式接口:

在这里插入图片描述

函数描述符:
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作 函数描述符。
例如,Runnable接口可以看作一个什么也不接受什么也不返回(void)的函数的 签名,因为它只有一个叫作run的抽象方法,
这个方法什么也不接受,什么也不返回(void)。
Java重用了函数式接口提 供的标准类型,并将其映射成一种形式的函数类型。 

在这里插入图片描述

Java 8的库设计师帮你在java.util.function包中引入了几个新的函数式接:Predicate、Consumer 、Function
https://blog.csdn.net/a879611951/article/details/80104014   四大核心函数接口
Function<T, R> 
T:入参类型,R:出参类型
调用方法:R apply(T t); 
定义函数示例:Function<Integer, Integer> func = p -> p * 10;    // 输出入参的10倍
调用函数示例:func.apply(10);    // 结果100
例如:
Function<Integer, Integer> fun1 = n->n*2 ;
fun1.apply(3);

public static void main(String[] args) {
    List<Integer> weights = Arrays.asList(7, 3, 4, 10);
    Function<Integer, Apple> intConsumer = Apple::new;
    List<Apple> apples = map(weights,Apple::new);
    System.out.println(JSON.toJSONString(apples));
}
public static List<Apple> map(List<Integer> list, Function<Integer, Apple> f) {
    List<Apple> result = new ArrayList<>();
    for (Integer e : list) {
        Apple apply = f.apply(e);
        result.add(f.apply(e));
    }
    return result;
}
运行结果:[{"weight":7},{"weight":3},{"weight":4},{"weight":10}]


Supplier<T>
T:出参类型;没有入参
调用方法:T get();
定义函数示例:Supplier<Integer> supplier= () -> 100;    // 常用于业务“有条件运行”时,符合条件再调用获取结果的应用场景;运行结果须提前定义,但不运行。
调用函数示例:supplier.get();
例如:
Supplier<String> supplier = String::new;
System.out.println(supplier.get());//""
Supplier<Emp> supplierEmp = Emp::new;
Emp emp = supplierEmp.get();
emp.setName("dd");
System.out.println(emp.getName());//dd


Consumer<T>
T:入参类型;没有出参
调用方法:void accept(T t);
定义函数示例:Consumer<String> consumer= p -> System.out.println(p);    // 因为没有出参,常用于打印、发送短信等消费动作
调用函数示例:consumer.accept("18800008888");

Predicate<T>              
 用于判断,  定义的函数只会返回true或false  
例如: Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isEmpty1 = (String str) ->str.isEmpty();
T:入参类型;出参类型是Boolean
调用方法:boolean test(T t);
定义函数示例:Predicate<Integer> predicate = p -> p % 2 == 0;    // 判断是否、是不是偶数
调用函数示例:predicate.test(100);    // 运行结果true
Consumer<String> aa= a-> System.out.println(a);
Consumer<String> aa1= System.out::println;
getLowCaloricDishesNamesInJava8(Dish.menu).forEach(aa);
public static List<String> getLowCaloricDishesNamesInJava8(List<Dish> dishes){
    //Dish类 calories变量   getCalories 是calories变量的get方法
    Comparator<Dish> comparing = comparing(Dish::getCalories);
    Function<Dish, String> getName = Dish::getName;

    List<String> collect = dishes.stream()
            .filter(d -> d.getCalories() < 400)
            .sorted(comparing(Dish::getCalories))
            .map(Dish::getName)
            .collect(toList());
    return collect;
}

https://www.cnblogs.com/lijingran/p/8708037.html                java编程Consumer和Predicate案例
//修改属性的值
  @Test
    public void test(){
        UserT userT = new UserT("zm");
        //接受一个参数
        Consumer<UserT> userTConsumer = userT1 -> userT1.setName("zmChange");};
    userTConsumer.accept(userT);
    logger.info(userT.getName());//输出zmChange
}

public class PredicateConsumerDemo {
    public static Student updateStudentFee(Student student, Predicate<Student> predicate, Consumer<Student> 
){
        if (predicate.test(student)){
            consumer.accept(student);
        }
        return student;
    }

}

public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("Ashok","Kumar", 9.5);

        student1 = updateStudentFee(student1, student -> student.grade > 8.5, student -> student.feeDiscount = 30.0);
        student1.printFee(); 

        Student student2 = new Student("Rajat","Verma", 8.0);
        student2 = updateStudentFee(student2, student -> student.grade >= 8, student -> student.feeDiscount = 20.0);
        student2.printFee();

    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值