Lambda表达式

生命日历在这里插入图片描述

<一个格子代表一周,寿命按90岁来算,一生有这么多的格子>

为了让自己的拖延症能够得到控制,做个生命日历一起提示自己吧 -QAQ-

Lambda表达式

函数式编程思想

函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做

冗余的Runnable代码

举例我们需要一个线程去完成任务:

//面向对象思想
Runnable task = new Runnable() {
			@Override
			public void run() { // 覆盖重写抽象方法
				System.out.println("多线程任务执行!");
			}
		};
		new Thread(task).start(); // 启动线程

奔着Java一切皆对象思想,我们需要创建一个Runnable接口的匿名内部类对象来指定任务内容 ,在将其交给线程进行启动.

//Lambda表达式写法

new Thread(()->System.Out println("多线程任务执行了")).Start();
//

两个写法的执行结构一样的,Lambda表达式相对更加简便<只能简化匿名内部类的写法>

好处:

使得代码更简洁,可读性强
传递行为,而不止是传递值,更便于功能复用
流的并行化操作

2014年3月Oracle所发布的Java 8(JDK 1.8)中,加入了Lambda表达式的重量级新特性,为我们打开了新世界的大门。
Lambda表达式在后面学习的C++的STL算法库、python、ruby、scala等经常使用

看了些大佬写的Lambda入门,非常nice-------->大佬Lambda第一篇入门
第二个链接地址------------------->第二篇的入门

1.1 概念

Lambda表达式就是对匿名内部类对象的一种格式的简化。
强调的是做什么,而不是怎么做
语体结构相对简化,但Java内部编程应用普及程度不高

组成:

由3部分组成

1.参数列表 ()
2. 箭头 ->
3.语句体<方法体> {}

4种样式或简写格式

lambda表达式参数列表的参数类型 < int等 > 可以省略
如果Lambda体中语句只有一句,那么大括号可以省略
如果大括号中只有一条语句,并且是return语句<大括号同时省略>return可以省略

格式1:

无参数无返回值
() -> System.out.println(“格式1”);

格式2:

有参无返回
(x) -> System.out.println(“格式2”+x);

格式3:

有n参数,无返回
(n1, n2) -> System.out.println(“格式3”+n1+n2);

格式4:

有参,有返回语句体有多个语句
(n1, n2) -> {int result = n1 + n2; return result;}
有参有返回单条语句
(n1,n2)->n1+n2

常见的Lambda表达式

Runnable r = ()-> System.out.println("线程被执行了");
Consumer<String>  con = out::println;//引用其他类中定义好的静态方法
Function<String,Integer> fun1 =Integer::parseInt; //把数字类型的字符串转换成数字
Predicate<Integer> p1 = (x) -> x>0;  //大于0的正数
s = s.filter((x) -> x.startsWith("张")); //Stream流,取首个汉字为张的name

目标类型:

目标类型是函数式接口<接口只能有一个显示声明的抽象方法为函数式接口>
Lambda表达式使用的前提,就是接口必须是一个函数式接口

函数式接口

只有一个抽象方法,那么这个接口就是函数式接口
注解: @FunctionalInterface
使用注解来检查当前接口是否是一个函数式接口
如果不是函数式接口,则编译报错。<注解可有可无>

常用函数式接口

JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在java.util.function包中被提供。
JDK 8 中多了个注解 @FunctionalInterface。这就是为何能在 JDK 8 中可以使用这种箭头式的 Lambda 写法。

函数式接口参数类型返回类型说明
Consumer< T >
消费型接口
Tvoid对类型为T的对象操作,方法:void accept(T t)
Supplier< T>
供给型接口
T返回类型为T的对象,方法:T get();可用作工厂
Function<T, R>
函数型接口
TR对类型为T的对象操作,并返回结果是R类型的对象。方法:R apply(T t);
Predicate< T>
断言型接口
Tboolean判断类型为T的对象是否满足条件,并返回boolean 值。方法boolean test(T t);

其他接口

函数式接口参数类型返回类型用途
BiFunction<T,U,R>T,UR对类型为T,U参数应用操作,返回R类型的结果。包含方法为Rapply(Tt,Uu);
UnaryOperator(Function子接口)TT对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为Tapply(Tt);
BinaryOperator(BiFunction子接口)T,TT对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为Tapply(Tt1,Tt2);
BiConsumer<T,U>T,Uvoid对类型为T,U参数应用操作。包含方法为void accept(Tt,Uu)
ToIntFunctionToLongFunctionToDoubleFunctionTint,long,double分别计算int、long、double、值的函数
IntFunctionLongFunctionDoubleFunctionint,long,doubleR参数分别为int、long、double类型的函数

消费型接口

Consumer< T >

抽象方法

void accept(T t);
有参无返回

作用:

当某个函数可以接收一个数据,并且处理这个数据,处理完成之后,不需要返回任何数据,这个函数需要当做数据来进行传递,就使用消费型接口。

示例:提供一个方法,最终打印花了多少钱,干了什么事?

package com.cn.day;

import java.util.function.Consumer;

public class A {
    public static void main(String[] args) {
    
        //这个接口提供一个方法能帮助我们打印做什么事
        Consumer<String> con=(str)-> System.out.println(str);
        test(500,"补课",con);

    }
    public static void test(int money, String str, Consumer<String> con){
        System.out.println("花了"+money);
        con.accept(str);

    }
}

接口此处简化的内容就是Consumer接口中的accept方法;

Consumer<String> con = new Consumer<String>() {
			public void accept(String str){
				System.out.println(str);
			}
		};

方法引用
使用lambda格式实现一个函数式接口,如果接口方法已经被其他对象实现,就不需要再次调用这个实现,直接使用

使用格式如下:

  • 函数式接口 名称 = 对象名 :: 方法名称
  • 函数式接口 名称 = 类名 :: 静态方法名

比如:

Function<String,Integer> fun1 =Integer::parseInt;

作用

把已经实现的方法,作为一个数据,作为一个引用,赋值给某个函数式接口引用
可以把这个引用当做方法的返回值,也可以作为方法的实际参数进行传递

方法引用的三种方式实例展示:

class A2{
    public static void main(String[] args) {
//        Consumer<String > consumer=(x)-> System.out.println("Hello");
//        consumer.accept("Hello");
        //调用JDKSystem.Out对象已有的println方法
        Consumer<String >consumer1=System.out::println;
        consumer1.accept("Hello");
        //调用自定义方法
        A2 a2 = new A2();
        Consumer<String> con2=a2::Mymethod1;
        con2.accept("名字");
        //调用自定义静态方法
        int[] x={1,2,3,4};
        Consumer<int[]>con3= A2::Mymethod2;
        con3.accept(x);

    }



    public  void Mymethod1(String str) {
         str="杨小益";
        System.out.println(str);

    }

    public static void Mymethod2(int[] arr) {
        for (Integer integer : arr) {

            System.out.println(integer);
        }
    }
}
		

供给型接口

Supplier< T >

抽象方法

T get()
无参有返回
使用 在若需要定义方法 这个方法不需要任何参数,返回需要的数据

作用

若需要定义函数,生成一个需要的数据,函数需要当成数据进行传递,可以使用供给型接口

示例:

class GJ{
    public static void main(String[] args) {
         /*
	 定义一个方法,返回一个集合,集合中n个满足要求的数据

	 要求数据是随机数字,要在1-10之间
    * */
        Supplier<Integer>sup=()->{
            Random random = new Random();
            int num=random.nextInt(10)+1;
            return num;
        };
        ArrayList<Integer> arraylist = getArraylist(3, sup);
        for (Integer integer : arraylist) {
            System.out.println(integer);
        }

    }

    private static ArrayList<Integer> getArraylist(int i, Supplier<Integer> sup) {
        ArrayList<Integer> integers = new ArrayList<>();
        for (int j = 0; j < i; j++) {
            integers.add(sup.get());
        }
        return integers;
    }
}

函数式接口

Function<T, R>

抽象方法

R apply(T t)
有参数,有返回值,传入一个对象T,返回对象R

andThen(Function f):在调用者处理方式之后,再进行参数的处理方式处理

作用:

如果需要定义一个函数,接收一个数据,将数据进行处理,完成之后,还能返回一个结果,就可以使用函数型接口。

示例:

需求:定义一个方法,传入一个String的变量, 把字符串转换成数字 并乘10后返回。

class HanShu{
//    需求:定义一个方法,传入一个String的变量,
//    把字符串转换成数字 并乘10后返回。
public static void main(String[] args) {
    Function<String,Integer>function=(string)->
        Integer.parseInt(string);


    Integer i = getStringToInt("822", function);
    System.out.println(i);

}

    private static Integer getStringToInt(String s, Function<String, Integer> function) {
        Integer apply = function.apply(s);
        return apply;
    }
}

断言型接口

Predicate< T >

抽象方法

boolean test(T t)
有参有返回
判断对象T,返回Boolean值


其他功能

Predicate and(Predicate pre):在调用者条件判断之后,再由参数条件判断,返回两个条件的都满足的判断对象

Predicate or(Predicate pre):返回两个条件任意一个满足的判断对象

Predicate negate():返回的是调用者判断条件的取反

示例:

需求:下面的方法需要可以对Arravlist进行数据的过滤
比如:正数,负数等过滤方式
最终可以返回一个满足条件的Arrartist集合

class Duanyan{
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(66);
        list.add(666);
        list.add(35);
        list.add(-20);
        list.add(0);
        list.add(33);
        Predicate<Integer>p1=(x)->x>=0;
        List<Integer> list1 = filterZhengshu(list,p1);
        System.out.println(list1);


        Predicate<Integer>p2=(x)->x<0;
        List<Integer> list2=filterFushu(list,p2);
        System.out.println(list2);
    }

    private static List<Integer> filterFushu(ArrayList<Integer> list, Predicate<Integer> p2) {
        ArrayList<Integer> list1 = new ArrayList<>();
        for (Integer integer : list) {
            if (p2.test(integer)){
                list1.add(integer);
            }
        }
        return list1;

    }

    private static List<Integer> filterZhengshu(ArrayList<Integer> list, Predicate<Integer> p1) {
        ArrayList<Integer> list1 = new ArrayList<>();
        for (Integer integer : list) {
            if(p1.test(integer)){
                list1.add(integer);
            }
        }
        return list1;
    }

}

Stream流的并行化操作

过滤:filter

可以通过filter方法将一个流转换成另一个子集流。

Stream<T> filter(Predicate<? super T> predicate);

该接口接收一个Predicate函数式接口参数作为筛选条件。

统计个数:count

流提供count方法来数一数其中的元素个数:

long count();

该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。

取用前几个:limit

limit方法可以对流进行截取,只取用前n个

Stream<T> limit(long maxSize);

参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作

跳过前几个:skip

使用skip方法获取一个截取之后的新流:

Stream<T> skip(long n);

组合:concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)

备注:这是一个静态方法,与java.lang.String当中的concat方法是不同的。

逐一处理:forEach

将流中的数据,根据Consumer描述的处理方式,进行处理。
void forEach(Consumer<? super T> action);
该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理

stream可以对数据进行过滤
比不断的自定义循环,要简单很多。

public class Demo2 {
	public static void main(String[] args) {
		//Collection单列集合的获取   直接使用对象的stream()方法获取即可
		HashSet<String> set = new HashSet<>();
		Stream<String> s = set.stream();
		//Map的获取   先把其转换成单列集合在通过stram()获取流对象
		HashMap<String, String> map = new HashMap<>();
		//对KEY过滤
		Set<String> ss = map.keySet();
		Stream<String> s1 = ss.stream();
		//对Value过滤
		Collection<String> values = map.values();
		Stream<String> s3 = values.stream();
		//对entry项过滤
		Set<Map.Entry<String, String>> entries = map.entrySet();
		Stream<Map.Entry<String, String>> s4 = entries.stream();
		//数组的获取   Stream中有一个of的静态方法
		int[] arr = {1,2,3,4,5};

		Stream<int[]> s5 = Stream.of(arr);


	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值