千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆

你所不知道的Lambda表达式和常用的函数式接口

匿名提问者 2023-03-27 15:22:00

你所不知道的Lambda表达式和常用的函数式接口

我要提问

推荐答案

  同学,您好!你所不知道的Lambda表达式和常用的函数式接口

Lambda表达式

  一. 什么是Lambda表达式

  Lambda表达式是JDK1.8中新增的一种方式,用于替代匿名内部类,该表达式可以让开发人员更加关注于具体需要传递的方法,而不是因为需要传递一个方法而创建一个对象。

  二. Lambda表达式

  1. 基本语法

  Lambda省去⾯向对象的条条框框,格式由3个部分组成:

  参数部分

  箭头

  代码块

  比如:(参数类型 参数名称) -> { 代码语句 }

  2. 格式说明

  ⼩括号内的语法与传统⽅法参数列表⼀致:⽆参数则留空;多个参数则⽤逗号分隔;

  -> 是新引⼊的语法格式,代表指向动作;

  ⼤括号内的语法与传统⽅法体要求基本⼀致。

  3. Lambda的省略格式

  所谓的Lambda表达式的省略原则是:可推导即可省略。

  Lambda强调的是“做什么”⽽不是“怎么做”,所以凡是可以根据上下⽂推导得知的信息,都可以省略。

  3.1 省略规则

  在Lambda标准格式的基础上,使⽤省略写法的规则为:

  ⼩括号内参数的类型可以省略;

  如果⼩括号内有且仅有⼀个参,则⼩括号可以省略;

  如果⼤括号内有且仅有⼀个语句,则⽆论是否有返回值,都可以省略⼤括号、return关键字及语句、分号。

  4. Lambda的使用前提

  Lambda的语法⾮常简洁,完全没有⾯向对象复杂的束缚,但是使⽤时有⼏个问题需要特别注意:

  使⽤Lambda必须具有接⼝,且要求接⼝中有且仅有⼀个抽象⽅法。 ⽆论是JDK内置的

  Runnable 、 Comparator 接⼝还是⾃定义的接⼝,只有当接⼝中的抽象⽅法存在且唯⼀时,才可以使用Lambda

  2. 使⽤Lambda必须具有上下⽂推断。 也就是⽅法的参数或局部变量类型必须为Lambda对应的接⼝

  类型,才能使⽤Lambda作为该接⼝的实例。

  5. 常用函数式接口

  JDK提供了⼤量常⽤的函数式接⼝以丰富Lambda的典型使⽤场景,它们主要在 java.util.function

  包中被提供. 常用的函数式接口包括以下四个。

  5.1 Supplier接⼝

  java.util.function.Supplier 接⼝仅包含⼀个⽆参的⽅法: T get() 。⽤来获取⼀个泛型参数,可以指定类型的对象数据。由于这是⼀个函数式接⼝,这也就意味着对应的Lambda表达式需要“对外提供”⼀个符合泛型类型的对象数据。

  5.1.1 基本使用方式如下:

  public class SupplierDemo {

  // 为了获取一个int类型的数据

  private static int getNum(Supplier supplier) {

  // get方法 -- 返回一个指定数据类型 T 的数据

  return supplier.get();

  }

  public static void main(String[] args) {

  // int num = getNum(new Supplier() {

  // @Override

  // public Integer get() {

  // return 50;

  // }

  // });

  System.out.println(getNum(() -> 50));

  // 1. 获取30 60 两个数字中的最大值

  // getNum(new Supplier() {

  // @Override

  // public Integer get() {

  // return Math.max(30, 60);

  // }

  // });

  getNum(()->Math.max(30, 60));

  // 有一个数组

  int[] nums = {1,5,4,8,4,51,2,1,6,8};

  // 通过getNum方法获取数组的最大值

  // getNum(new Supplier() {

  // @Override

  // public Integer get() {

  // Arrays.sort(nums);

  // return nums[nums.length - 1];

  // }

  // });

  int num = getNum(() -> {

  Arrays.sort(nums);

  return nums[nums.length - 1];

  });

  System.out.println(num);

  }

  }

  5.2 Consumer接⼝

  java.util.function.Consumer 接⼝则正好与Supplier接⼝相反,它不是⽣产⼀个数据,⽽是消费⼀个数据,其数据类型由泛型决定。

  Consumer 接⼝中包含抽象⽅法 void accept(T t) ,意思是说消费⼀个执⾏泛型的数据

  Consumer 接⼝中包含默认⽅法:andThen

  如果⼀个⽅法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,⾸先做⼀个操作, 然后再做另⼀个操作,实现组合。⽽这个⽅法就是 Consumer 接⼝中的default⽅法 andThen

  5.2.1 下⾯是JDK的源代码:

  default Consumer andThen(Consumer after) {

  Objects.requireNonNull(after);

  return (T t) -> { accept(t); after.accept(t); };

  }

  基本使用方式如下:

  public class ConsumerDemo {

  // 使用一个指定的String类型的数据

  private static void useString(Consumer consumer, String string){

  consumer.accept(string);

  }

  private static void useString(Consumer consumer, Supplier supplier) {

  consumer.accept(supplier.get());

  }

  // 返回的Consumer对象的目的 -- 使用accept方法接收参数,传递给first和second使用

  private static Consumer andThen(Consumer first, Consumer second){

  return new Consumer() {

  @Override

  public void accept(String s) {

  first.accept(s);

  second.accept(s);

  }

  };

  }

  private static void andThenTest(Consumer first, Consumer second, String string){

  // Consumer then = first.andThen(second);

  // then.accept(string);

  // 前后两个接口对象之间,没有数据上的联系

  // 两个接口 分别处理的都是原本的数据

  first.andThen(second).accept(string);

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

  Consumer consumer = andThen(first, second);

  consumer.accept(string);

  }

  public static void main(String[] args) {

  // useString(new Consumer() {

  // @Override

  // public void accept(String s) {

  // System.out.println(s.length());

  // }

  // }, "lambda");

  // useString((String s)->{

  // System.out.println(s.length());

  // }, "lambda");

  useString(s->System.out.println(s.length()), "lambda");

  // useString(s-> System.out.println(s), "lambda");

  // useString(System.out::println, "lambda");

  useString(s-> {

  System.out.println(s.concat(Integer.valueOf(s.length()).toString()));

  System.out.println(s + s.length());

  }, "lambda");

  useString(s->{

  System.out.println(s.length());

  },()->{

  return "123456oiuytr";

  });

  andThenTest(s -> System.out.println(s.toUpperCase()),

  s->System.out.println(s.substring(0, 3)), "lambda Exp");

  }

  }

  5.3 Predicate接⼝

  有时候我们需要对某种类型的数据进⾏判断,从⽽得到⼀个boolean值结果。这时可以使

  ⽤java.util.function.Predicate接⼝。

  Predicate 接⼝中包含⼀个抽象⽅法: boolean test(T t)

  该接口也存在三个默认的方法,分别是and 、 or 和negate, 分别表示与 、或 、非三种逻辑处理。

  5.3.1 接口代码示例:

  public class PredicateDemo {

  private static boolean testMethod(Predicate predicate, String s){

  // test方法返回一个boolean类型的数据

  return predicate.test(s);

  }

  private static boolean andMethod(Predicate first, Predicate second, String s){

  return first.and(second).test(s);

  }

  private static boolean orMethod(Predicate first, Predicate second, String s) {

  return first.or(second).test(s);

  }

  private static boolean negateMethod(Predicate predicate, String s) {

  return predicate.negate().test(s);

  }

  public static void main(String[] args) {

  // 1. 判断一个字符串是否是由txt结尾的

  // boolean result = testMethod(new Predicate() {

  // @Override

  // public boolean test(String s) {

  // return s.endsWith("txt");

  // }

  // }, "newFile");

  // boolean result = testMethod((String s)->{

  // return s.endsWith("txt");

  // }, "newFile");

  boolean result = testMethod(s->s.endsWith("txt"), "newFile");

  System.out.println(result);

  boolean r1 = andMethod(s -> s.length() > 6,

  s -> s.startsWith("a"), "asijhgvbnm");

  boolean r2 = orMethod(s -> s.length() > 6,

  s -> s.equals("abcd"), "asdfghjkl");

  boolean r3 = negateMethod(s -> s.endsWith("a"), "asdfghjkl");

  System.out.println(r1 + " - " + r2 + " - " + r3);

  }

  }

  5.4 Function接⼝

  java.util.function.Function接⼝⽤来根据⼀个类型的数据得到另⼀个类型的数据,前者称为前置条件,后者称为后置条件。

  Function 接⼝中最主要的抽象⽅法是: R apply(T t) ,根据类型T的参数获取类型R的结果。

  Function接⼝中有⼀个默认的andThen⽅法,⽤来进⾏组合操作。

  5.4.1 基本使用方式如下

  public class FunctionDemo {

  private static void applyMethod(Function function, String s){

  Integer apply = function.apply(s);

  System.out.println("从字符串" + s + "中获取的integer类型数据是:" + apply);

  }

  private static Function andThen(Function first, Function second){

  // T = String; R = Integer; V=Boolean

  // String --> Boolean

  return new Function() {

  @Override

  public Boolean apply(String s) {

  // String --> Integer

  Integer apply = first.apply(s);

  // Integer --> Boolean

  Boolean apply1 = second.apply(apply);

  return apply1;

  }

  };

  }

  private static void andThenMethod(Function first, Function second, String s){

  Function then = first.andThen(second);

  // 因为andThen方法在实现的时候 前面一个的结果给后面一个处理

  // 前者T R --> 后者 R V ==> T --> V

  Boolean apply = then.apply(s);

  System.out.println(apply);

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

  Function function = andThen(first, second);

  Boolean b = function.apply(s);

  System.out.println(b);

  }

  public static void main(String[] args) {

  // applyMethod(new Function() {

  // @Override

  // public Integer apply(String s) {

  // return s.indexOf("a");

  // }

  // }, "fashjkl");

  // applyMethod((String s)->{

  // return s.indexOf("a");

  // }, "fashjkl");

  applyMethod(s->s.indexOf("a"), "fashjkl");

  andThenMethod(s-> s.length(),

  i -> i > 20, "sadfghjkl;");

  // andThenMethod(String::length,

  // i -> i > 20, "sadfghjkl;");

  }

  }

  现在你学会Lambda表达式怎么用了吗?

猜你喜欢LIKE

Css3有哪些新特性

2023-03-27

Vue开发相对于原生的js开发有什么优点

2023-03-27

为什么不能用break?

2023-03-27

最新文章NEW

Vue3.0和Vue2.0的区别

2023-03-27

什么是权限管理?权限管理有哪些分类

2023-03-27

在成都参加java程序员培训班要多少钱?

2023-03-27