栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

01-函数式接口和 lambda 表达式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

01-函数式接口和 lambda 表达式

本文写的是java8新特性中的函数式接口、lambda表达式,介绍一下它们的 是什么怎么用
若想了解java8其它新特性,请到 00-java8常用新特性文章索引 阅读。

1 函数式接口 1.1 是什么

只包含一个抽象方法的接口,不是规定接口中只能有一个方法,因为接口中还可以包含 default方法和 static 方法。

  • 在接口上声明@FunctionalInterface注解,可以检查该接口是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
  • 使用 lambda 表达式可以创建一个函数式接口的实例(下面介绍)。
1.2 Java内置的四大核心函数式接口

JDK中提供了一些默认的函数式接口,能够满足大部分业务场景,当然,也可以通过自定义的函数式接口处理业务。

1.2.1 Consumer

消费型接口:对给定的 T 类型的参数,进行操作,
核心方法:void accept(T t);

源码

@FunctionalInterface
public interface Consumer {

    
    void accept(T t);

    
    default Consumer andThen(Consumer after) {
 Objects.requireNonNull(after);
 return (T t) -> { accept(t); after.accept(t); };
    }
}

1.2.2 Supplier

供给型接口: 获取一个 T 类型的对象
核心方法:T get();

源码

@FunctionalInterface
public interface Supplier {

    
    T get();
}

1.2.3 Function

函数型接口: 对 T 类型的参数进行操作,返回 R 类型的结果
核心方法:R apply(T t);

源码

@FunctionalInterface
public interface Function {

    
    R apply(T t);

    
    default  Function compose(Function before) {
 Objects.requireNonNull(before);
 return (V v) -> apply(before.apply(v));
    }

    
    default  Function andThen(Function after) {
 Objects.requireNonNull(after);
 return (T t) -> after.apply(apply(t));
    }

    
    static  Function identity() {
 return t -> t;
    }
}

1.2.4 Predicate

断定型接口: 判断 T 类型的参数,是否满足某约束,返回 boolean 值
核心方法:boolean test(T t);

源码

@FunctionalInterface
public interface Predicate {

    
    boolean test(T t);

    
    default Predicate and(Predicate other) {
 Objects.requireNonNull(other);
 return (t) -> test(t) && other.test(t);
    }

    
    default Predicate negate() {
 return (t) -> !test(t);
    }

    
    default Predicate or(Predicate other) {
 Objects.requireNonNull(other);
 return (t) -> test(t) || other.test(t);
    }

    
    static  Predicate isEqual(Object targetRef) {
 return (null == targetRef)
  ? Objects::isNull
  : object -> targetRef.equals(object);
    }
}
1.3 四大核心函数式接口简单使用

四大核心函数式接口简单使用



public class FuncIntfTest {

    
    public static final int LENGTH = 2;

    
    public static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};


    public static void main(String[] args) {
 int setLength = 5;// set 的 length
 Set set = new linkedHashSet<>();

 Supplier supplier = getRandomHexStrSupplier();// 获取一个 Supplier:随机十六进制字符串生成器
 for (int i = 0; i < setLength; i++) {
     set.add(supplier.get());//生成随机 16 进制字符串
 }
 Consumer setConsumer = getSetConsumer();//获取一个Consumer: 遍历打印 Set
 System.out.println("----------打印所有的16进制字符串---------");
 setConsumer.accept(set);//遍历打印 set 中的每个元素

 //将字符串转为 long 值
 Function toDecimalFunction = new Function() {
     @Override
     public Long apply(String s) {
  Long value = Long.valueOf(s, 16);//将16进制字符串转为10进制的long值
  return value;
     }
 };

 Predicate lt150Predicate = new Predicate() {
     
     @Override
     public boolean test(String s) {
  Long value = Long.valueOf(s, 16);
  return value.longValue() < 150;
     }
 };

 Set longSet = new linkedHashSet<>();
 for (String str : set) {
     if (lt150Predicate.test(str)) {//判断一个十六进制字符串是否小于150
  Long value = toDecimalFunction.apply(str);//将16进制字符串转为10进制的long值
  longSet.add(value);
     }
 }
 System.out.println("----------打印小于150的值---------");
 setConsumer.accept(longSet);//遍历打印 longSet 中的每个元素
    }

    
    private static Supplier getRandomHexStrSupplier() {
 Supplier supplier = new Supplier() {

     
     @Override
     public String get() {
  Random random = new Random();
  StringBuilder sb = new StringBuilder();
  for (int i = 0; i < LENGTH; i++) {
      sb.append(hexChars[random.nextInt(hexChars.length)]);
  }
  return sb.toString();
     }
 };
 return supplier;
    }

    
    private static Consumer getSetConsumer() {
 Consumer consumer = new Consumer() {

     
     @Override
     public void accept(Set set) {
  if (set == null || set.isEmpty())
      return;
  for (Object s : set) {
      System.out.println(s);
  }
     }
 };
 return consumer;
    }
}

运行结果:

----------打印所有的16进制字符串---------
48
B1
0B
46
5F
----------打印小于150的值---------
72
11
70
95
1.4 Java其他内置的函数式接口
函数式接口 参数类型 返回类型 用途
BiFunction T, U R 对类型为 T, U 参数应用操作,
返回 R 类型的结果。
核心方法为 R apply(T t, U u);
UnaryOperator
(Function子接口)
T T 对类型为T的对象进行一元运算,
并返回T类型的结果。
核心方法为T apply(T t);
BinaryOperator
(BiFunction 子接口)
T, T T 对类型为T的对象进行二元运算,
并返回T类型的结果。
核心方法为T apply(T t1, T t2);
BiConsumer T, U void 对类型为T, U 参数应用操作。
核心方法为void accept(T t, U u)
ToIntFunction
ToLongFunction
ToDoubleFunction
T int/long/double T 类型的参数,
返回intlongdouble 类型的结果,
核心方法为intlongdouble applyAsInt(T value);
IntFunction
LongFunction
DoubleFunction
int/long/double R 参数分别为int、long、double 类型的函数,
返回 R 类型的结果,
核心方法: R apply(intlongdouble value);
2、 Lambda 表达式

作用:可以通过 Lambda 表达式来创建函数式接口的对象,这样可以取代大部分的匿名内部类,可优化代码结构,写出更加优雅的代码。

2.1 Lambda 是什么

Java8中引入了一个新的操作符 “->” 该操作符称为箭头操作符或 Lambda 操作符
箭头操作符将 Lambda 表达式拆分成两部分:
左侧:参数列表
右侧:业务逻辑代码, 即 Lambda 体

2.2 Lambda 简单使用

可以看出 lambda 表达式的代码量更少,更加简洁。

    
    @Test
    public void test00() {
 Random random = new Random();
 // 匿名内部类创建一个 Runable 对象
 Thread thread = new Thread(new Runnable() {
     @Override
     public void run() {
  System.out.println("匿名内部类:" + random.nextInt(10));
     }
 });
 thread.start();
 // lambda 表达式创建一个 Runable(函数式接口) 对象
 Runnable rLambda = () -> System.out.println("lambda表达式1:" + random.nextInt(10));
 Thread tLambda1 = new Thread(rLambda);
 tLambda1.start();

 //lambda 可以代替函数式接口的匿名内部类作为参数传递
 Thread tLambda2 = new Thread(() -> System.out.println("lambda表达式2:" + random.nextInt(10)));
 tLambda2.start();
    }

运行结果:

匿名内部类:8
lambda表达式1:2
lambda表达式2:5
2.3 类型推断

Lambda表达式中的类型推断,实际上是Java 7就引入的目标类型推断的扩展,Java7中的菱形操作符,它可使javac推断出泛型参数的类型。

 List list1 = new ArrayList();
 List list2 = new ArrayList<>();

Lambda 表达式中的参数类型依赖于上下文环境,是由编译器推断出来的。lambda表达式中无需指定类型,亦可编译通过。

// 类型推断,lambda可以推断出参数 str 的类型为String
Consumer c = str -> System.out.println(str);
2.3 Lambda 语法格式

Lambda 语法格式分别从 参数lambda体 进行介绍

2.3.1 参数:无参

参数:无参,参数部分为 ()

    
    @Test
    public void test01() {
 // 参数:无参,参数部分为 ()
 Supplier supplier = () -> {
     int num = new Random().nextInt(10);
     System.out.println(num);
     return num;
 };
 System.out.println(supplier.get());
    }

运行结果:

4
2.3.2 参数:只有一个参数

参数:只有一个参数,可以省略括号 ()

    
    @Test
    public void test02() {
 // 参数:只有一个参数,可以省略括号 ()
 Consumer c1 = str -> {
     System.out.println(str);
 };
 c1.accept("hello lambda");
    }

运行结果:

hello lambda
2.3.3 参数:多个参数

参数:多个参数,所有的参数写在小括号 () 中

    
    @Test
    public void test03() {
 //参数:多个参数,所有的参数写在小括号 () 中
 BinaryOperator binaryOperator = (n1, n2) -> {
     return n1 + n2;
 };
 System.out.println(binaryOperator.apply(2, 3));
    }

运行结果:

5
2.3.4 lambda体:一行语句,无返回值

lambda体:一行语句,无返回值,可以省略大括号


    
    @Test
    public void test04() {
 // lambda体:一行语句,返回值,可以省略大括号
 Consumer c1 = str -> System.out.println(str);
 c1.accept("lambda体:一行语句,返回值,可以省略大括号");
    }

运行结果:

lambda体:一行语句,返回值,可以省略大括号
2.3.5 lambda体:一行语句,有返回值

lambda体:一行语句,有返回值,可以省略 return 关键字 和 大括号

    
    @Test
    public void test05() {
 // 二元运算:加法
 BinaryOperator biOpr1 = (n1, n2) -> {
     return n1 + n2;
 };
 // 二元运算:乘法
 // lambda体:一行语句,有返回值,可以省略 return 关键字 和 大括号
 BinaryOperator biOpr2 = (n1, n2) -> n1 * n2;

 System.out.println(biOpr1.apply(5, 10));
 System.out.println(biOpr2.apply(5, 10));
    }

运行结果:

15
50
2.3.6 lambda体:多行语句

lambda体:多行语句,所有代码语句要写在大括号 {} 中

    
    @Test
    public void test06() {

 // 二元运算:加法
 // lambda体:多行语句,所有代码语句要写在大括号 {} 中
 BinaryOperator biOpr1 = (n1, n2) -> {
     System.out.println("参数一:" + n1);
     System.out.println("参数二:" + n2);
     return n1 + n2;
 };
 System.out.println("加法运算结果:" + biOpr1.apply(5, 10));
    }

运行结果:

参数一:5
参数二:10
加法运算结果:15

好了,函数式接口lambda 表达式的简单介绍就到这,多加理解,学以致用,才是王道。

代码:
https://github.com/wengxingxia/001java8.git


转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号