JAVA8新特性Lambda表达式语法及运用

本文深入探讨Java 8引入的Lambda表达式及其在Stream API中的应用,讲解Lambda表达式的基本概念、语法和常见函数式接口,同时介绍Stream API的操作流程及常用方法,帮助读者提升代码效率和开发技能。

前言

Lambda表达式是jdk1.8新增的一个特性,学习它可以解决我们项目中的代码冗余问题、提高我们的开发效率、精简代码、学习它对以后钻研源码非常重要。

什么是Lambda?

1.Lambda概述

  1. Lambda表达式也被称为箭头函数、匿名函数、闭包
  2. Lambda表达式体现的是轻量级函数式编程思想
  3. ->符号是Lambda表达式核心操作符号,符号左边是操作参数,右边是操作表达式

2.为什么要使用Lambda?

首先它不是解决未知问题的新技术,它只是对现有的解决方案实现语意优化,使用的时候需要根据实际需求来考虑性能问题。

我们来看一个简单的例子对比一下Lambad和传统方法,很明显它把非业务部分都去除了,解决的代码的冗余。

package com.liyingdong;
public class Test1 {
	public static void main(String[] args) {
//         传统模式的创建线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				 System.out.println("传统线程:"+Thread.currentThread().getId());
			}
		}).start();
		
//	  jdk1.8新特性  Lambda创建线程
		new Thread(()->{
			 System.out.println("Lambda线程:"+Thread.currentThread().getId());
		}) .start();
	}
}

Lambda表达式的基础知识

1.函数式接口

函数式接口,是java类型系统中的接口,函数式接口只能包含一个抽象方法,并且接口类要使用语义化检测注解@FunctionalInterface标记,可以有静态方法和默认方法,默认方法可以被从写。
有一个注意的点就是函数式接口它是继承与obj的,所以它可以定义从父类继承的方法,是可以通过函数式语法语义的检测的,例如String toString();

package com.liyingdong;
@FunctionalInterface
public interface IMessageFormat {
   String format(String message, String format);
    String toString();
    static boolean verifyMessage(String msg) {
        if (msg != null) {
            return true;
        }
        return false;
    }
}

2.Lambda表达式和函数式接口的关系

  1. 函数式接口,只包含一个操作方法
  2. Lambda表达式,只能操作一个方法
  3. java中的Lambda表达式,核心就是一个函数式接口的实现

3.jdk中常见的函数式接口

java.util.function提供了大量的函数式接口

Predicate 接收参数T对象,返回一个boolean类型结果

Consumer 接收参数T对象,没有返回值

Function 接收参数T对象,返回R对象

Supplier 不接受任何参数,直接通过get()获取指定类型的对象

UnaryOperator 接口参数T对象,执行业务处理后,返回更新后的T对象

BinaryOperator 接口接收两个T对象,执行业务处理后,返回一个T对象

 // 三、JDK8 提供的常见函数式接口
        Predicate<String> pre = (String username) -> {
            return "admin".equals(username);
        };

        System.out.println(pre.test("ddm"));
        System.out.println(pre.test("admin"));

        Consumer<String> con = (String message) -> {
            System.out.println("要发送的消息:" + message);
            System.out.println("消息发送完成");
        };
        con.accept("好嗨哦!..");
        con.accept("感觉人生已经到达了高潮.");

        Function<String, Integer> fun = (String gender) -> {
            return "male".equals(gender)?1:0;
        };
        System.out.println(fun.apply("male"));
        System.out.println(fun.apply("female"));

        Supplier<String> sup = () -> {
            return UUID.randomUUID().toString();
        };
        System.out.println(sup.get());
        System.out.println(sup.get());
        System.out.println(sup.get());

        UnaryOperator<String> uo = (String img)-> {
            img += "[100x200]";
            return img;
        };

        System.out.println(uo.apply("原图--"));

        BinaryOperator<Integer> bo = (Integer i1, Integer i2) -> {
            return i1 > i2? i1: i2;
        };

        System.out.println(bo.apply(12, 13));

输出:
在这里插入图片描述

4.Lambda表达式基本语法

分别为两种:

第一种:带参数的Lambda表达式

第二种:带返回值的Lambda表达式

声明: 就是和lambda表达式绑定的接口类型,

参数: 含在一对圆括号中,和绑定的接口中的抽象方法中的参数个数及顺序一致。

操作符:->

执行代码块: 包含在一对大括号中,出现在操作符号的右侧, [接口声明] = (参数) -> {执行代码块};

我们定义几个内部接口来实现案例来实现Lambda表达式,前提是必须和接口进行绑定。

 // 没有参数,没有返回值的lambda表达式绑定的接口
    interface ILambda1{
        void test();
    }

    // 带有参数,没有返回值的lambda表达式
    interface ILambda2{
        void test(String name, int age);
    }

    // 带有参数,带有返回值的lambda表达式
    interface ILambda3 {
        int test(int x, int y);
    }

1.Lambad执行无参的接口方法。

ILambda1 i1 = () -> {
            System.out.println("好嗨哦!");
            System.out.println("感觉人生已经到达了高潮!");
        };

如果只是单纯的打印的话没必要两行,直接一行解决。

 ILambda1 i2 = () -> System.out.println("好震撼!");
        i2.test();

2.执行带两个参数的Lambad方法

ILambda2 i21 = (String n, int a) -> {
            System.out.println(n + "今年 " + a);
        };
        i21.test("我", 18);

3.lambda表达式的参数,可以附带0个到n个参数,括号中的参数类型可以不用指定,jvm在运行时,会自动根据绑定的抽象方法中电参数进行推导。

 ILambda2 i22 = (n, a) -> {
            System.out.println(n + "今年" + a + "岁了.");
        };
        i22.test("我", 22);

4.lambda表达式的返回值,如果代码块只有一行,并且没有大括号,不用写return关键字,单行代码的执行结果,会自动返回。
如果添加了大括号,或者有多行代码,必须通过return关键字返回执行结果。

ILambda3 i31 = (x, y) -> x + y;
        System.out.println(i31.test(100, 200));

结果:

在这里插入图片描述

5.Lambda表达式类型检查

举例下面,基于函数式接口的定义jvm底层自动的实现了类型推导。
这里注明一下别的点Lambda是不适用于重载的。

package com.liyingdong;
import java.util.ArrayList;
import java.util.List;
public class Test3{
    public static void test(MyInterface<String, List> inter) {
        List<String> list = inter.strategy("hello", new ArrayList());
        System.out.println(list);
    }
//    传统方式
    public static void main(String[] args) {
        test(new MyInterface<String, List>() {
            @Override
            public List strategy(String s, List list) {
                list.add(s);
                return list;
            }
        });
//        表达式方式
        test((x, y) -> {
            y.add(x);
            return y;
        });
    }
}
@FunctionalInterface
interface MyInterface<T, R> {
    R strategy (T t, R r);
}

结果:
在这里插入图片描述

6.方法引用

这里的话方法用分为两种,静态引用、实例引用。

静态引用语法:对象::静态方法

实例引用语法:实例化对象::方法

package com.liyingdong;
import java.util.*;
class Person {
    private String name;
    private String gender;
    private int age;

    public Person () {}
    public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Person(String name, String gender, int age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", gender=" + gender + ", age=" + age + "]";
	}
	// 静态方法引用
    public static int compareByAge(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}
class PersonUtil {
    // 实例方法引用
    public int comprareByName(Person p1, Person p2) {
        return p1.getName().hashCode() - p2.getName().hashCode();
    }
}
interface IPerson {
    Person getPerson(String name, String gender, int age);
}
public class Test {
    public static void main(String[] args) {
        List<Person> list = new ArrayList<Person>();
        list.add(new Person("海王", "男", 29));
        list.add(new Person("海叼", "男", 16));
        list.add(new Person("海班", "男", 20));
        list.add(new Person("猴头菇", "女", 30));

        // 匿名内部类实现
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        // lambda表达式实现
        Collections.sort(list, (p1, p2) -> p1.getAge() - p2.getAge());
        // 静态方法引用实现
        Collections.sort(list, Person::compareByAge);

        // 实例方法引用
        PersonUtil pu = new PersonUtil();
        Collections.sort(list, pu::comprareByName);

        list.forEach(System.out::println);
        IPerson p1 = Person::new;
        
        Person person = p1.getPerson("东", "男", 18);
        System.out.println(person);
    }
}

输出:
在这里插入图片描述

Stram操作集合的常用方法

一般的话使用Lambda最常用的方式就是函数式接口配合Stram下面介绍一下 Stram操作集合的常用方法。

(1)stream的处理流程

  • 1. 数据源
    
  •  2. 数据转换
    
  • 3. 获取结果
    

(2)获取Stream对象

从集合或者数组中获取[**]

  1. Collection.stream()
  2. accounts.stream()
  3. Arrays.stream(T t)

使用缓冲流BufferReader

BufferReader.lines()-> stream()

等等方式…

(3)中间操作API{intermediate}

操作结果是一个Stream,中间操作可以有一个或者多个连续的中间操作,需要注意的是,中间操作

只记录操作方式,不做具体执行,直到结束操作发生时,才做数据的最终执行。

中间操作:就是业务逻辑处理。

无状态:数据处理时,不受前置中间操作的影响。

  1. map
  2. filter
  3. peek
  4. parallel
  5. sequential
  6. unordered

有状态:数据处理时,受到前置中间操作的影响。

  1. distinct
  2. sorted
  3. limit
  4. skip

(4)终结操作|结束操作

需要注意:一个Stream对象,只能有一个结束操作,这个操作一旦发生,就会真实处理数据,生成对应的处理结果。

非短路操作:当前的Stream对象必须处理完集合中所有 数据,才能得到处理结果。

  1. forEach
  2. forEachOrdered
  3. toArray
  4. reduce
  5. collect
  6. min
  7. max
  8. count
  9. iterator

短路操作:当前的Stream对象在处理过程中,一旦满足某个条件,就可以得到结果。

  1. anyMatch
  2. allMatch
  3. noneMatch
  4. findFirst
  5. findAny

使用案例:

package com.liyingdong.test;

import java.util.*;
import java.util.stream.Stream;

public class Test7 {

    public static void main(String[] args) {
        // 1. 批量数据 -> Stream对象
        // 多个数据
        Stream stream = Stream.of("admin", "login", "ddd");

        // 数组
        String [] strArrays = new String[] {"sss", "dsda"};
        Stream stream2 = Arrays.stream(strArrays);

        // 列表
        List<String> list = new ArrayList<>();
        list.add("dd1");
        list.add("dd2");
        list.add("dd3");
        list.add("dd4");
        list.add("dd5");
        Stream stream3 = list.stream();

        // 集合
        Set<String> set = new HashSet<>();
        set.add("qq1");
        set.add("qq2");
        set.add("qq3");
        Stream stream4 = set.stream();

        // Map
        Map<String, Integer> map = new HashMap<>();
        map.put("tt", 1000);
        map.put("ttt", 1200);
        map.put("ttt", 1000);
        Stream stream5 = map.entrySet().stream();

        // 2. Stream对象对于基本数据类型的功能封装
        // int / long / double
//        IntStream.of(new int[] {10, 20, 30}).forEach(System.out::println);
//        IntStream.range(1, 5).forEach(System.out::println);
//        IntStream.rangeClosed(1, 5).forEach(System.out::println);

        // 3. Stream对象 --> 转换得到指定的数据类型
        // 数组
//        Object [] objx = stream.toArray(String[]::new);

        // 字符串
//        String str = stream.collect(Collectors.joining()).toString();
//        System.out.println(str);

        // 列表
//        List<String> listx = (List<String>) stream.collect(Collectors.toList());
//        System.out.println(listx);

        // 集合
//        Set<String> setx = (Set<String>) stream.collect(Collectors.toSet());
//        System.out.println(setx);

        // Map
//        Map<String, String> mapx = (Map<String, String>) stream.collect(Collectors.toMap(x->x, y->"value:"+y));
//        System.out.println(mapx);

        // 4. Stream中常见的API操作
        List<String> accountList = new ArrayList<>();
        accountList.add("taijun");
        accountList.add("haiwang");
        accountList.add("liyingdong");
        accountList.add("tangle");
        accountList.add("liubiao");
        accountList.add("ddd");
        accountList.add("cc");

        // map() 中间操作,map()方法接收一个Functional接口
//        accountList = accountList.stream().map(x->"梁山好汉:" + x).collect(Collectors.toList());

        // filter() 添加过滤条件,过滤符合条件的用户
//        accountList = accountList.stream().filter(x-> x.length() > 5).collect(Collectors.toList());

        // forEach 增强型循环
//        accountList.forEach(x-> System.out.println("forEach->" + x));
//        accountList.forEach(x-> System.out.println("forEach->" + x));
//        accountList.forEach(x-> System.out.println("forEach->" + x));

        // peek() 中间操作,迭代数据完成数据的依次处理过程
//        accountList.stream()
//                .peek(x -> System.out.println("peek 1: " + x))
//                .peek(x -> System.out.println("peek 2:" + x))
//                .forEach(System.out::println);

//        accountList.forEach(System.out::println);

        // Stream中对于数字运算的支持
        List<Integer> intList = new ArrayList<>();
        intList.add(20);
        intList.add(19);
        intList.add(7);
        intList.add(8);
        intList.add(86);
        intList.add(11);
        intList.add(3);
        intList.add(20);

        // skip() 中间操作,有状态,跳过部分数据
//        intList.stream().skip(3).forEach(System.out::println);

        // limit() 中间操作,有状态,限制输出数据量
//        intList.stream().skip(3).limit(2).forEach(System.out::println);

        // distinct() 中间操作,有状态,剔除重复的数据
//        intList.stream().distinct().forEach(System.out::println);

        // sorted() 中间操作,有状态,排序

        // max() 获取最大值
        Optional optional = intList.stream().max((x, y)-> x-y);
        System.out.println(optional.get());
        // min() 获取最小值

        // reduce() 合并处理数据
        Optional optional2 = intList.stream().reduce((sum, x)-> sum + x);
        System.out.println(optional2.get());
    }
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值