2020了你还不会Java8新特性?Lambda表达式及API(二)

lambda表达式

为什么要使用lambda表示式

  • 在Java中无法将函数座位参数传递给一个方法,也无法返回一个函数的方法。
  • 在js中,函数的参数是一个函数。返回值是另一个函数的情况是非常常见的。是一门经典的函数式语言。

Java匿名内部类。

匿名内部类的介绍

Gradle的使用。可以完全使用maven的中央仓库。
进行安卓的开发时,gradle已经成为标配了。

lambda:
匿名内部类

 my_jButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button Pressed! ");
            }
        });

改造后

        my_jButton.addActionListener(e -> System.out.println("Button Pressed!"));

lambda表达式的基本结构:

(param1,param2,param3) ->{

}

函数式编程: 一个接口里边只有一个抽象方法。
可以通过lambda表达式来实例。

关于函数式接口:

  • 如果一个借口只有一个抽象方法,那么该接口就是一个函数式接口。
  • 如果我们在某一个接口上声明了functionalInterface注解,那么编译器就会按照函数是借口的定义来要求改接口。
  • 如果某个接口只有一个抽象方法,但是我们并没有给接口声明functionnaleInterface注解,编译器依旧会给改接口看作是函数式接口。

通过实例对函数式接口的理解:

package com.erwa.jdk8;

@FunctionalInterface
interface MyInterface {

    void test();

//    Multiple non-overriding abstract methods found in interface com.erwa.jdk8.MyInterface
//    void te();

    //如果一个接口声明一个抽象方法,但是这个方法重写了 object类中的一个方法.
    //接口的抽象方法不会加一.所以依然是函数方法.
    // Object 类是所有类的父类.
    @Override
    String toString();
}

public class Test2 {

    public void myTest(MyInterface myInterface) {
        System.out.println(1);
        myInterface.test();
        System.out.println(2);
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.myTest(() -> {
            System.out.println(3);
        });
    }

}

接口里边从1.8开始也可以有方法实现了。default

    默认方法。
   default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
 
 * <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor reference

lambda表达式的作用:

  • lambda表达式为Java添加了确实的函数式编程特性,使我们能将函数当做一等公民看待。
  • 在将函数座位一等公民的语言中,lambda表达式的类型是函数。但是在Java中,lambda表达式是对象,他们必须依附于一类特别的对象类型-函数式接口(function interface)

迭代的方式:

  • 外部迭代:
  • 内部迭代:
  • 方法引用:
list.forEach(System.out::println);

接口中可以有默认方法和静态方法。

流: stream

 /**
     * Returns a sequential {@code Stream} with this collection as its source.
     *
     * <p>This method should be overridden when the {@link #spliterator()}
     * method cannot return a spliterator that is {@code IMMUTABLE},
     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
     * for details.)
     *
     * @implSpec
     * The default implementation creates a sequential {@code Stream} from the
     * collection's {@code Spliterator}.
     *
     * @return a sequential {@code Stream} over the elements in this collection
     * @since 1.8
     */
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

关于流方式实现的举例:

public static void main(String[] args) {
        //函数式接口的实现方式
        MyInterface1 i1 = () -> {};
        System.out.println(i1.getClass().getInterfaces()[0]);
        MyInterface2 i2 = () -> {};
        System.out.println(i2.getClass().getInterfaces()[0]);

        // 没有上下文对象,一定会报错的.
//        () -> {};

        //通过lambda来实现一个线程.
        new Thread(() -> System.out.println("hello world")).start();

        //有一个list  ,将内容中的首字母变大写输出.
        List<String> list = Arrays.asList("hello","world","hello world");
        //通过lambda来实现所有字母编程大写输出.
//        list.forEach(item -> System.out.println(item.toUpperCase()));
        //把三个单词放入到新的集合里边.
        List<String> list1 = new ArrayList<>();  //diamond语法. 后边的<>不用再放类型
//        list.forEach(item -> list1.add(item.toUpperCase()));
//        list1.forEach(System.out::println);

        //进一步的改进. 流的方式
//        list.stream();//单线程
//        list.parallelStream(); //多线程
        list.stream().map(item -> item.toUpperCase()).forEach(System.out::println);//单线程
        list.stream().map(String::toUpperCase).forEach(System.out::println);

        //上边的两种方法,都满足函数式接口的方式.
    }

lambda表达式的作

  • 传递行为,而不仅仅是值

    • 提升抽象层次
    • API重用性更好
    • 更加灵活

lambda基本语法

  • (argument) -> (body)
  • 如: (arg1,arg2...) -> (body)

Java lambda结构

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

高阶函数:
如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数.

传递行为的举例:

  public static void main(String[] args) {
        // 函数的测试
        // 传递行为的一种方式.
        FunctionTest functionTest = new FunctionTest();
        int compute = functionTest.compute(1, value -> 2 * value);

        System.out.println(compute);
        System.out.println(functionTest.compute(2,value -> 5+ value));
        System.out.println(functionTest.compute(3,a -> a * a));

        System.out.println(functionTest.convert(5, a -> a + "hello "));

        /**
         * 高阶函数:
         * 如果一个函数接收一个函数作为参数,或者返回一个函数作为返回值,那么该函数就叫做高阶函数.
         */

    }

    //使用lambda表达式的话,可以直觉预定义行为.用的时候传递.
    // 即 函数式编程.
    public int compute(int a, Function<Integer, Integer> function) {
        return function.apply(a);
    }

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

    // 之前完成行为的做法. 提前把行为定义好,用的时候调用方法. 如:
    public  int method1(int a ){
        return a * 2 ;
    }

Function类中提供的默认方法的讲解:

/**
     * 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.
     返回一个组合的函数。对应用完参数后的结果,再次运行apply
     *
     * @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));
    }

compose : 组合function, 形成两个function的串联。 先执行参数

andThen :先应用当前的函数apply,然后再当做参数再次执行apply。 后执行参数。

identity:输入什么返回什么。

BiFunction: 整合两个函数的方法。
为什么BiFunction不提供 compose ,只提供andThen呢?
因为如果提供compose方法的话,只能获取一个参数的返回值。不合理。

  public static void main(String[] args) {
        FunctionTest2 functionTest2 = new FunctionTest2();

        // compose
//        System.out.println(functionTest2.compute(2,a -> a * 3,b -> b * b));
        // andThen
//        System.out.println(functionTest2.compute2(2,a -> a * 3,b -> b * b));

        //BiFunction
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a - b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a * b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a + b));
//        System.out.println(functionTest2.compute3(1,2, (a,b) -> a / b));

        //BiFunction  andThen
        System.out.println(functionTest2.compute4(2,3,(a,b) ->a + b , a -> a * a ));
    }

    //compose : 组合function, 形成两个function的串联。  先执行参数
    //andThen :先应用当前的函数apply,然后再当做参数再次执行apply。 后执行参数

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

    public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
        return function1.andThen(function2).apply(a);
    }

    //BiFunction
    //求两个参数的和
    //先定义一个抽象的行为.
    public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) {
        return biFunction.apply(a, b);
    }

    //BiFunction  andThen
    public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) {
        return biFunction.andThen(function).apply(a, b);
    }

测试 函数式接口的实例:


public class PersonTest {
    public static void main(String[] args) {

        List<Person> personList = new ArrayList<>();

        personList.add(new Person("zhangsan", 20));
        personList.add(new Person("zhangsan", 28));
        personList.add(new Person("lisi", 30));
        personList.add(new Person("wangwu", 40));

        PersonTest test = new PersonTest();

        //测试 getPersonUsername
//        List<Person> personList1 = test.getPersonUsername("zhangsan", personList);
//        personList1.forEach(person -> System.out.println(person.getUsername()));

        //测试  getPersonByAge
        List<Person> personByAge = test.getPersonByAge(25, personList);
        personByAge.forEach(person -> System.out.println(person.getAge()));

        //测试第三种: 自定义输入行为
        List<Person> list = test.getPersonByAge2(20,personList,(age,persons) ->{
            return persons.stream().filter(person -> person.getAge() > age).collect(Collectors.toList());
        });
        list.forEach(person -> System.out.println(person.getAge()));

    }

    public List<Person> getPersonUsername(String username, List<Person> personList) {
        return personList.stream().filter(person -> person.getUsername().equals(username)).collect(Collectors.toList());
    }

    public List<Person> getPersonByAge(int age, List<Person> personList) {
        //使用BiFunction的方式
//        BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> {
//            return  list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList());
//        };

        //变换之后:
        BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) ->
            list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList());

        return biFunction.apply(age, personList);
    }

     //第三种方式, 动作也让用户自己定义传进来
    public List<Person> getPersonByAge2(int age ,List<Person> list,BiFunction<Integer,List<Person>,List<Person>> biFunction){
        return biFunction.apply(age, list);
    }
}

函数式接口的真谛: 传递的是行为,而不是数据

  public static void main(String[] args) {
        //给定一个输入参数,判断是否满足条件,满足的话返回true
        Predicate<String> predicate = p -> p.length() > 5;
        System.out.println(predicate.test("nnihaoda"));

    }

到现在为止,只是讲解了Java.lang.function包下的几个最重要的,经常使用的方法。



2020年1月3日08:06:28
BinaryOperator 接口

public class SinaryOpertorTest {

    public static void main(String[] args) {

        SinaryOpertorTest sinaryOpertorTest = new SinaryOpertorTest();

        System.out.println(sinaryOpertorTest.compute(1,2,(a,b) -> a+b));

        System.out.println("-- -- - - - -- -");

        System.out.println(sinaryOpertorTest.getMax("hello123","world",(a,b) -> a.length() - b.length()));
    }

    private int compute(int a, int b, BinaryOperator<Integer> binaryOperator) {
        return binaryOperator.apply(a, b);
    }

    private String getMax(String a, String b, Comparator<String> comparator) {
        return BinaryOperator.maxBy(comparator).apply(a, b);
    }
}

Optional final :Optional 不要试图用来当做参数, 一般只用来接收返回值,来规避值的空指针异常的问题。

  • empty()
  • of()
  • ofNullable()
  • isPresent()
  • get()
  • ...
public class OptionalTest {

    public static void main(String[] args) {
        Optional<String> optional = Optional.of("hello");

        //不确定是否为 空是 调用和这个方法
//        Optional<String> optional2 = Optional.ofNullable("hello");

//        Optional<String> optional1 = Optional.empty();

        //过时
//        if (optional.isPresent()) {
//            System.out.println(optional.get());
//        }

        optional.ifPresent(item -> System.out.println(item));
        System.out.println(optional.orElse("nihao"));
        System.out.println(optional.orElseGet(() -> "nihao"));

    }
public class OptionalTest2 {
    public static void main(String[] args) {
        Employee employee = new Employee();
        employee.setName("dawa");

        Employee employee1 = new Employee();
        employee1.setName("erwa");

        List<Employee> list = Arrays.asList(employee, employee1);
        Company company = new Company("gongsi", list);

        Optional<Company> optionalCompany = Optional.ofNullable(company);

        System.out.println(optionalCompany.map(company1 -> company1.getList()).orElse(Collections.emptyList()));
    }
}

原文地址:https://www.cnblogs.com/wobushitiegan/p/12145163.html

时间: 2024-10-17 05:30:25

2020了你还不会Java8新特性?Lambda表达式及API(二)的相关文章

Java核心技术之Java8新特性-Lambda表达式

1 总体说明 Java8新特性概述 函数式接口 Lambda表达式(闭包) 2 Java8新特性概述 Oracle公司于2014年3月发布了Java8正式版,该版本是自JDK5.0以来最具革命性的版本. Java8为Java语言.编译器.类库和JVM带来了大量的新特性.接下来的内容将会详细说明Java8在Java语言方面的新特性以及它们的使用场景. 3 函数式接口 Java8引入的一个核心概念是函数式接口(Functional Interfaces):如果一个接口定义一个唯一的抽象方法,那么这个

java8新特性——Lambda表达式

上文中简单介绍了一下java8得一些新特性,与优点,也是为本次学习java8新特性制定一个学习的方向,后面几篇会根据上文中得新特性一一展开学习.本文就从java8新特性中比较重要的Lambda表达式开始学学习. 一.为什么要使用Lambda表达式 Lambda是一个匿名函数,我们可以baLambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁,更灵活的代码.作为一种更紧凑得代码风格,使得java得语言表达能力得到提升.Lambda表达式需要函数式接口的支持,接口中

Java8新特性 - Lambda表达式 - 基本知识

A lambda expression is an unnamed block of code (or an unnamed function) with a list of formal parameters and abody. Java8中的lambda表达式不同于C#,使用的是-> eg: // Takes an int parameter and returns the parameter value incremented by 1 (int x) -> x + 1 // Take

Java8新特性 - Lambda 表达式

 是什么? Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 属于函数式编程思想,允许把函数作为一个方法的参数(函数作为参数传递进方法中). 怎么使用? 使用前提: 必须支持上下文推导,要能够推导出来 Lambda 表达式表示的是哪个接口中的内容. 可以使用接口当做参数,然后传递 Lambda 表达式(常用),也可以将 Lambda 表达式赋值给一个接口类型的变量. Lambda 表达式的省略规则: 小括号中的参数类型可以省略. 如果小括号中只有一个

java8新特性-Lambda表达式(二)

Java8新增了java.util.funcion包,里面包含常用的函数接口,这是Lambda表达式的基础,Java集合框架也新增部分接口,以便与Lambda表达式对接. Collections中的常用函数接口 Java集合框架的接口继承结构: 上图中蓝色标记和橙色标记的接口类,表示在Java8中加入了新的接口方法,由于继承关系,他们相应的子类也会继承这些方法. 下面用一张表列举这些方法 接口名 Java8新加入的方法 Collection removeIf() spliterator() st

2020了你还不会Java8新特性?(四)Collector类源码分析

Collector类源码分析 jdk8是怎么对底层完成支持的.不了解底层,平时用还可以,但是遇到问题的时候就会卡在那里.迟迟灭有解决方案.在学习一门新技术时,先学习怎么去用,不要执着于源码.但是随着用的越来越多,你去了解底层是比较好的一种学习方法. 有多种方法可以实现同一个功能.什么方式更好呢? 越具体的方法越好. 减少自动装箱拆箱操作 collect : 收集器 Collector作为collect方法的参数. Collector作为一个接口.它是一个可变的汇聚操作,将输入元素累计到一个可变的

2020了你还不会Java8新特性?(五)收集器比较器用法详解及源码剖析

收集器用法详解与多级分组和分区 为什么在collectors类中定义一个静态内部类? static class CollectorImpl<T, A, R> implements Collector<T, A, R> 设计上,本身就是一个辅助类,是一个工厂.作用是给开发者提供常见的收集器实现.提供的方法都是静态方法,可以直接调用. 函数式编程最大的特点:表示做什么,而不是如何做.开发者更注重如做什么,底层实现如何做. /** * Implementations of {@link

Java8新特性——lambda表达式.(案例:词频统计)

需求:读入一个文本文件,确定所有单词的使用频率并从高到低排序,打印出所有单词及其频率的排序列表 先用传统方法解: 1 package cn._1.wordfrequency; 2 3 import java.util.HashSet; 4 import java.util.Map; 5 import java.util.Set; 6 import java.util.TreeMap; 7 import java.util.regex.Matcher; 8 import java.util.reg

Java8新特性——lambda表达式.(案例:完全数分类)

需求:输入一个数,判断其类型(完全数,过剩数,不足数) 完全数:自身之外所有因数和==自身 过剩数:自身之外所有因数和>自身 不足数:自身之外所有因数和<自身 1 package cn._3.numberclassifier; 2 3 //BEGIN number_classifier_java8 4 import java.util.List; 5 import java.util.stream.IntStream; 6 7 import static java.lang.Math.sqrt