jdk8的新特性:Lambda表达式、Stream API

jdk8的新特性

	Lambda表达式
	StreamAPI
	支持并行
	Nashorn引擎:jvm中可以运行js
	Optional类:减少空指针异常
	接口中可以有静态和默认方法
	新日期

lambda表达式

一、理解
Lambda表达式 是满足一定条件的匿名内部类的代替,也就是一段可以传递的代码。
条件:匿名内部类实现的接口只有一个抽象方法

method(()->System.out.println());
等价于
method(Runnable s){
	public void run(){
		System.out.println();
	}
}

二、好处
语法更加简洁,更加紧凑,使JAVA语言的表达能力得到了提升!

三、应用场景
1、直接作为接口的实例出现,赋值给接口
Runnable r = ()->System.out.println();
2、作为实参传递给方法
method(()->System.out.println());

四、语法
由三部分组成:
(参数列表)->{抽象方法的实现体或Lambda体}

注意:

1.参数列表中的参数类型可以省略
2.参数列表中如果仅仅有一个参数,则小括号可以省略
3.Lambda体中只有一句话,大括号可以省略
4.Lambda体中仅有的一句话是返回语句,则return关键字也可以省略.

函数式接口

只有一个抽象方法的接口,就称为函数式接口,比如:Runnable、Comparator,我们可以在接口上使用 @FunctionalInterface注解,检查它是否是一个函数式接口
java内置核心的四大函数式接口

消费型接口Consumer<T>
		 void accept(T t)

供给型接口Supplier<T>
		T get()

函数型接口Function<T,R>
		R apply(T t)

断定型接口Predicate<T>
		boolean test(T t)

在这里插入图片描述

方法引用

一、理解:

方法引用属于Lambda表达式的一种,相当于满足一定要求的Lambda表达式,也可以作为函数式接口的实例

二、应用场景:

 * 1、作为实例赋值给函数式接口,相当于函数式接口的对象
 * 2、作为实参传递给形参为函数式接口类的方法

三、要求:

  1、Lambda体的实现里面仅仅只有一句话,而且是方法调用
  2、要调用的方法的参数列表和返回类型 必须和接口的抽象方法的参数类别和返回类型一致!
  3、备注:如果要调用的方法的调用者正好为抽象方法的第一个参数,其他参数和返回类型一致,这个时候可以使用类名::普通方法 形式!

四、语法:

类名或对象::方法名

分类:

  对象::普通方法名
  类名::静态方法名
  类名::普通方法名  ☆ 

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

构造器引用

一、理解:

属于Lambda表达式的一种,作为函数式接口的实例出现的
满足一定要求的Lambda表达式可以改进成构造器引用!

二、语法:

类型::new

三、要求:

①Lambda中仅仅只有一句话
②lambda体中仅有的一句话为 返回一个new出来的对象(通过构造器创建对象)
③抽象方法和调用的构造器的参数列表以及返回一致

在这里插入图片描述

数组引用

一、理解:

 属于Lambda表达式的一种,作为函数式接口的实例出现的
 满足一定要求的Lambda表达式可以改进成数组引用!

二、语法:

数组类型[]::new

三、要求:

①Lambda中仅仅只有一句话
②Lambda体仅有的一句话为 返回一个new出来的数组
③抽象方法的参数正好为数组的长度

在这里插入图片描述

总结

匿名内部类>Lambda表达式>方法引用|构造器引用|数组引用

相同点:都是作为接口的实例出现!

不同点:
* 能用方法引用|构造器引用|数组引用 肯定能用  Lambda表达式 代替
* 能用Lambda表达式不一定能用方法引用|构造器引用|数组引用,必须满足一些要求!
* 能用 Lambda表达式 肯定能用 匿名内部类代替
* 能用匿名内部类的不一定能用Lambda表达式,必须满足一个要求:接口为函数式接口!

Stream API

特点

①Stream 不是集合,自己不会存储元素,集合将的是数据,Stream讲的是计算。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。必须搞清楚有哪些数据才能往下执行,这意味着他们会等到需要结果的时候才执行。

④Stream只能“消费”一次,如果想继续做其他操作,需要重新获取stream对象

④更像一个高级的iterator,单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,但是可以并行化数据! \(^o^)/

使用步骤

 * 1、开始操作:获取Stream对象,创建一个stream对象指向一个具体的数据源
 * 2、中间操作:处理,对数据源进行处理,返回一个stream类型新结果
 * 3、终止操作:最后要一个结果

在这里插入图片描述
获取stream对象:

方式一:根据集合获取stream对象
方式二:根据数组获取stream对象
方式三:分句一组序列值获取stream对象
方式四:创建无限流,根据一个规则获取stream对象
public class TestStreamStart {
	//方式一:根据集合获取Stream对象  (数据源:集合) ★
	@Test
	public void test1() {
		List<Employee> list = EmployeeData.getEmployees();
		//获取串行流对象
		Stream<Employee> stream = list.stream();
		//使用匿名内部类:
//		stream.forEach(new Consumer<Employee>(){
//			@Override
//			public void accept(Employee t) {
//				System.out.println(t);
//			}
//		});
		stream.forEach(System.out::println);
	}
	
	//方式二:根据数组获取Stream对象  (数据源:数组)
	@Test
	public void test2() {
		String[] arr = {"john","lucy","lily"};
		Arrays.stream(arr).forEach(System.out::println);
	}
	// 方式三:根据一组序列值获取Stream对象(数据源:一组值)
	@Test
	public void test3() {
		Stream<Character> of = Stream.of('a','b','c','d');
		of.forEach(System.out::println);
	}
	//方式四:生成无限流
	@Test
	public void test4() {
		//匿名内部类
//		Stream<Double> generate = Stream.generate(new Supplier<Double>(){
//			@Override
//			public Double get() {
//				return Math.random();
//			}
//		});

		//Lambda
//		Stream<Double> generate2 = Stream.generate(()->Math.random());
		//方法引用
		Stream<Double> generate3 =  Stream.generate(Math::random);
		generate3.forEach(System.out::println);		
	}
}

Stream 中间操作

  • ①惰性求值。 除非进行终止操作,否则前面的中间操作不会执行任何处理
  • ②中间操作执行终止操作后,属于“一次性消费”,不能再继续执行终止操作
  • ③多个中间操作可以形成流水线操作

常见方法:

筛选与切片:
	filter(Predicate p)——接收 Lambda , 从流中排除某些元素。
	limit(n)——截断流,使其元素不超过给定数量。
	skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
	distinct()——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
映射:
	map(Function<元素类型,R>)——映射,根据元素本身一一映射成新的元素
	flatMap(Function<元素类型,Stream>)——映射
排序:
	sorted()——自然排序
	sorted(Comparator)——定制排序
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

import org.junit.Before;
import org.junit.Test;
/**
 * 此类用于演示Stream的中间操作
 */
public class TestStreamMiddle {
	List<Employee> list;
	@Before
	public void before(){
		 list = EmployeeData.getEmployees();
	}
	//筛选与切片
	@Test
	public void test1() {
		//1.获取Stream对象
		Stream<Employee> stream = list.stream();
		//2.中间操作
		//filter:根据条件过滤
		Stream<Employee> filter = stream.filter(t->t.getAge()>30);
		//limit:用于限制最大元素个数
		Stream<Employee> limit = filter.limit(50);
		//skip:跳过指定的个数
		Stream<Employee> skip = limit.skip(3);
		//distinct:去重
		Stream<Employee> distinct = skip.distinct();

		//3.终止操作
		distinct.forEach(System.out::println);
	}
	
	//测试:映射
	@Test
	public void test2() {
		//1.获取Stream对象
		Stream<Employee> stream = list.stream();
		//2.中间操作
		//map:映射
//		Stream<String> map = stream.map(new Function<Employee,String>(){
//			@Override
//			public String apply(Employee t) {
//				return t.getName();
//			}});
		 	
		//Stream<String> map = stream.map(Employee::getName);
		
		//flatMap:映射
		//使用匿名内部类:
//		stream.flatMap(new Function<Employee,Stream<Object>>(){
//			@Override
//			public Stream<Object> apply(Employee t) {
//				return TestStreamMiddle.employeeToStream(t);
//			}
//		});
		
		//使用方法引用
		Stream<Object> flatMap = stream.flatMap(TestStreamMiddle::employeeToStream);
		
		//3.终止操作
		flatMap.forEach(System.out::println);
	}
	
	//测试排序
	@Test
	public void test3() {
		//1.获取stream对象
		Stream<Employee> stream = list.stream();
		
		//2.中间操作
		//sorted():根据元素本身的比较性实现自然排序
//		Stream<Employee> sorted = stream.sorted();
		//sorted(comparator):根据比较器实现定制排序
		//进阶1:使用匿名内部类
//		stream.sorted(new Comparator<Employee>(){
//			@Override
//			public int compare(Employee o1, Employee o2) {
//				return Double.compare(o2.getSalary(), o1.getSalary());
//			}
//		});
		//进阶2:使用Lambda
		Stream<Employee> sorted2 = stream.sorted((o1,o2)->Double.compare(o2.getSalary(), o1.getSalary()));
		//3.终止操作
		sorted2.forEach(System.out::println);
	}
	
	//自定义规则实现:将员工转换成Stream类型
	public static Stream<Object> employeeToStream(Employee e){
		Stream<Object> of = Stream.of(e.getName(),e.getAge(),e.getSalary(),e.getSex());
		return of;
	}
	
	//案例1:筛选与切片
	//过滤年龄>30&&性别=男&工资>100000
	@Test
	public void exec1() {
		list.stream().
		filter(t->t.getAge()>30).
		filter(t->t.getSalary()>100000).
		filter(t->t.getSex()=='男').
		forEach(System.out::println);
	}
	//案例2:筛选与切片
	//过滤:年龄>30的员工中的 第2条——第4条数据
	@Test
	public void exec2() {
		list.stream().filter(t->t.getAge()>30).skip(1).limit(3).forEach(System.out::println);
	}
	//案例3:映射
	//过滤:员工中包含字符“赵”的姓名
	@Test
	public void exec3() {
		list.stream().map(Employee::getName).filter(s->s.contains("赵")).distinct().forEach(System.out::println);;
	}
}

stream终止操作:

常见方法:

 * 	count:统计个数
 *  max(Comparator):求最大值
 *  min(Comparator):求最小值
 *  forEach(Consumer):内部迭代
 *  reduce(BinaryOperator<T>):归约、合并
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;

import org.junit.Before;
import org.junit.Test;
/**
 * 此类用于演示Stream的终止操作
 */
public class TestStreamEnd {
	List<Employee> list;
	@Before
	public void before(){
		 list = EmployeeData.getEmployees();
	}
	//测试:count  统计Stream中的元素个数
	@Test
	public void test1() {
		//1.获取stream对象
		Stream<Employee> stream = list.stream();
		//2.终止操作
		long count = stream.count();
		System.out.println(count);
	}
	
	//测试:max/min  获取Stream中的最大值或最小值
	@Test
	public void test2() {
		//1.获取stream对象
		Stream<Employee> stream = list.stream();
		//2.终止操作
//		Optional<Employee> max = stream.max((e1,e2)->Integer.compare(e1.getAge(), e2.getAge()));
		Optional<Employee> min = stream.min((e1,e2)->Integer.compare(e1.getAge(), e2.getAge()));
		System.out.println(min);
	}
	//测试:forEach 获取Stream中的内部迭代
	@Test
	public void test3() {
		//1.获取stream对象
		Stream<Employee> stream = list.stream();
		//2.终止操作
		stream.forEach(System.out::println);
	}
	
	//测试:reduce 归约,合并
	@Test
	public void test4() {
		//1.获取stream对象
		Stream<Employee> stream = list.stream();
		
		//2.终止操作
		/*
		 * BinaryOperator:
		 * 		T apply(T t1,T t2);
		 */
		
		//进阶1:匿名内部类:
//		stream.reduce(new BinaryOperator<Employee>(){
//			@Override
//			public Employee apply(Employee t, Employee u) {
//				return null;
//			}
//		});

		Stream<Double> map = stream.map(e->e.getSalary());
		Optional<Double> reduce = map.reduce((t,u)->t+u);
		System.out.println(reduce);
	}
	
	//测试reduce:归约合并
	@Test
	public void test4_2() {
		Optional<String> reduce = list.stream().map(Employee::getName).reduce((t,u)->t.concat(",").concat(u));
		System.out.println(reduce);
	}
	
	//案例1:统计工资>100000的个数
	@Test
	public void exec1() {
		long count = list.stream().filter(e->e.getSalary()>100000).count();
		System.out.println(count);
	}
	
	//练习:员工姓名中包含“黄”的员工个数
	@Test
	public void exec2() {
		//方式一:筛选
		long count = list.stream().filter(e->e.getName().contains("黄")).count();
		System.out.println(count);
		
		//方式二:map-reduce
		Optional<Integer> reduce = list.stream().filter(e->e.getName().contains("黄")).map(e->1).reduce((t,u)->t+u);
		System.out.println(reduce);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值