Java之JDK1.8新特性一(Lambda)

1、JDK8新特性简介

  • 速度更快:算法的优化(比如HashMap)、底层内存结构的优化(将永久区PremGen变成了元空间MetaSpace)
  • 代码更少(增加了新的语法Lambda表达式)
  • 强大的Stream API
  • 偏于并行
  • 最大化减少空指针异常 Optional
    tips:
    永久区属于堆heap(在jdk1.7之前,heap中分为了2个区:垃圾回收区和永久区);而元空间存储在物理内存上

2、函数式编程思想

  • 在数学中,函数指的是给定一个输入值,通过一套计算方案,最终给出结果值。 也就是拿什么东西做什么事。
  • 面向对象又过分的强调了必须要通过对象的形式来做某事。(重视做事的过程)
  • 而函数式编程强调“做什么,而不是以什么形式去做”。(重视做事的结果)

3、Lambda编程基础

3.1函数式接口

在学习Lambda之前,需要先搞清楚函数式接口
函数式接口:适用于函数式编程场景(Lambda表达式),接口中有且仅有一个抽象方法,且需要添加FunctionalInterface注解
示例代码如下:

@FunctionalInterface
interface Conver{
	void fun();
}
3.2Lambda表达式格式及说明

Lambda表达式的标准格式为: (参数类型 参数名称) ‐> { 代码语句 }
说明:

  • 小括号内的语法与传统方法参数列表一致
  • -> 是新引入的语法格式,代表指向动作 ,表示小括号前面的参数被用于后面{}里面的代码语句
  • 大括号内的语法与传统方法体要求基本一致,它实际上是对函数式接口里唯一的那个抽象方法的重写
3.3Lambda省略格式

Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。
省略规则如下:

  • 小括号内参数的类型可以省略;
  • 如果小括号内有且仅有一个参,则小括号可以省略;
  • 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
3.4代码实例

1)无参无返回值

@Test
publuic vode demo01(){
	//匿名内部类写法
	Runnable task = new Runnable() {
        @Override
        public void run() {
            System.out.println("多线程任务1");
        }
    };
    new Thread(task).start();
    
    //Lambda写法
    new Thread(()->{System.out.println("多线程任务2");}).start();
    //{}里面只有一条语句,可以省略{}和;
    new Thread(()->System.out.println("多线程任务3")).start();   
}

2)有参有返回值

//有参有返回值
@FunctionalInterface
interface Calculator{
    int calc(int a,int b);
}

public class LambdaDemo {
	@Test
    public void demo02() {
    	//需求:求两个整数和
        //int result = invokeCalc(10,20,(a,b)->{return a+b;});
        //可优化为下面代码
        int result = invokeCalc(10,20,(a,b)->a+b);
        System.out.println(result);
    }

    //两个int类型进行处理
    public int invokeCalc(int a,int b,Calculator c){
        return c.calc(a,b);
    }
}

3)参数、返回值类型为函数式接口类型

@Test
public void demo03() {
	//需求1:执行1个线程任务
	startThread(()->System.out.println("多线程"));
	
	//需求2:将数组按照由小到大顺序排序
	String[] arr = {"c","a","d","b"};
	Arrays.sort(arr,compara());
	System.out.println(Arrays.toString(arr));
}

//参数为函数式接口,执行1个线程操作
public void startThread(Runnable target){
	new Thread(target).start();
}

//返回值类型为一个函数式接口,返回一个比较器对象
public Comparator<String> compara(){
	return (a,b)->a.compareTo(b);
}
3.5Lambda的延迟执行

有些场景代码执行后,结果不一定会使用,这就造成了性能浪费。而Lambda具有延迟执行的特性,就可以很好的解决这个问题。
参考代码如下:

@FunctionalInterface
interface MessageBuilder{
	String append();
}

public class LambdaDemo {
	@Test
	public void demo04() {
		String msg1 = "hello";
		String msg2 = "world";
		//不论level,在调用log方法的时候,后面的参数一定要进行拼接操作
		log("2",msg1+msg2);
		
		//只有当level符合条件,才会去调用append方法,才会执行Lambda
		newLog("1",()->msg1+msg2);
	}
	
	//记录日志
	public void log(String level,String msg){
		if("1".equals(level)){
			System.out.println(msg);
		}
	}
	
	public void newLog(String level,MessageBuilder mb){
		if("1".equals(level)){
			System.out.println(mb.append());
		}
	}
}

4、Lambda编程进阶

公共定义的函数式接口
从jdk1.8开始提供了function包,该包针对于用户有可能做的函数式接口做了一个公共定义
最为核心的有四个接口:

  1. 功能性接口:Function<T, R>
    是对接收一个T类型参数,返回R类型的结果的方法的抽象
    抽象方法:R apply(T t)
    默认方法:andThen
    示例代码如下:
    @Test
	public void functionTest() {
		int num = fun("100",s->Integer.parseInt(s) );//字符串转成int类型
		System.out.println(num);
		
		//先将字符串转成int,再*10
		int result = method("5", s->Integer.parseInt(s), a->a *= 10);
		System.out.println(result);
	}
	
	//用于字符串处理
	public Integer fun(String s,Function<String,Integer> fun){
		return fun.apply(s);
	}
	
	//andThen:先执行一次apply操作,然后将第一次执行apply操作后获得的返回值作为参数再执行一次apply操作
	public int method(String s, Function<String,Integer> one,Function<Integer,Integer> two){
		return one.andThen(two).apply(s);
	}

andThen源码如下:

 	default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
  1. 消费型接口:Consumer<T>
    对应的方法类型为接收一个参数,没有返回值
    抽象方法:void accept(T t)
    默认方法:andThen
    示例代码如下:
	@Test
	public void consumerTest(){
		shopping(12345, m->System.out.println("花了"+m+"元买了包包"));
		
		//将"hElLo"转成大写输出,其次再转成小写输出
		fun("hElLo",s->System.out.println(s.toUpperCase()),
			s->System.out.println(s.toLowerCase()));
	}
	
	//花钱购物
	public void shopping(double money,Consumer<Double> con){
		con.accept(money);
	}
	
	//andThen:使用提供的参数执行两次操作
	public void fun(String str,Consumer<String> one,Consumer<String> two){
		one.andThen(two).accept(str);
	}

andThen源码如下:

	default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
  1. 供给型接口:Supplier<T>
    该接口对应的方法类型不接受参数,但是提供一个返回值
    抽象方法:T get()
    示例代码如下:
	@Test
	public void supplierTest(){
		//获取10个0~99之间的随机数
		List<Integer> list = getList(10, ()->new Random().nextInt(100));
		System.out.println(list);
	}

	//获取指定个数的Integer集合
	public List<Integer> getList(int count, Supplier<Integer> sup){
		List<Integer> list = new ArrayList<>();
		for(int i=0;i<count;i++){
			list.add(sup.get());
		}
		return list;
	}
  1. 断言型接口:Predicate<T>
    该接口对应的方法为接收一个参数,返回一个Boolean类型
    抽象方法:boolean test(T t)
    默认方法:and(与),or(或),negate(非)
    示例代码如下:
	@Test
	public void predicateTest(){
		List<String> list = Arrays.asList("Tom","Jerry","Tony");
		List<String> nl = filterList(list, s->s.startsWith("T"));//将所有以“T”开头的字符串放入集合中
		System.out.println(nl);

		//判断一个字符串既包含"H",又包含"O"
		boolean bool = andFun(s->s.contains("H"),s->s.contains("O"),"HelloOpen");
		System.out.println(bool);
		
		//判断一个字符串中是否含有"H"或者"O"
		bool = orFun(s->s.contains("H"),s->s.contains("O"),"HelloOpen");
		System.out.println(bool);
		
		//对给定操作进行非判定
		bool = negateFun(s->s.length()<5,"helloworld");
		System.out.println(bool);
	}
	
	//将满足条件的字符串放入集合中
	public List<String> filterList(List<String> list, Predicate<String> pre){
		List<String> nl = new ArrayList<>();
		for(String s:list){
			if(pre.test(s)){
				nl.add(s);
			}
		}
		return nl;
	}

	//and
	public boolean andFun(Predicate<String> one,Predicate<String> two,String s){
		return one.and(two).test(s);
	}
	
	//or
	public boolean orFun(Predicate<String> one,Predicate<String> two,String s){
		return one.or(two).test(s);
	}
	
	//negate
	public boolean negateFun(Predicate<String> pre,String s){
		return pre.negate().test(s);
	}

附:一些常用的其它接口
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值