Java8新特性

Java8中有一些新的知识与内容,接下来,写一下经常用到的一些特性

主要内容

  1. Lambda 表达式
  2. 函数式接口
  3. 方法引用与构建
  4. Stream API

Java8 新特性简介

  • 代码更快
  • 代码更少
  • 强大的 Stream API
  • 便于并行
  • 最大化减少空指针异常


一、Lambda 表达式

1.1 基本语法

Lambda 表达式基本语法:Java8 引入了一个新的操作符 “->”,该符号称为箭头或者 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分
左侧: lambda 表达式的参数列表
右侧: lambda 表达式所需执行的功能,即 lambda 体

语法格式一:无参数,无返回值
() -> System.out.println("hello world")
语法格式二:有一个参数,并且无返回值
(x) -> System.out.println(x)
语法格式三:只有一个参数,小括号可以省略不写
(x) -> System.out.println(x)
语法格式四:有两个或以上的参数,有返回值,并且 Lambda 体中有多条语句

Comparator<Integer> com = (x,y) -> {
	System.out.println("函数接口");
	return Integer.compare(x, y);
}

1.2 案例操作

// 带有一个参数的 Lambda 用法
@Test
public void test(){
	Consumer<String> con = (x) -> System.out.println(x);
	con.accept("hello")
}

// 带有两个参数的 Lambda  用法
@Test
public void test(){
	Comparator<Integer> com = (x, y) -> {
		System.out.println("函数型接口");
		return Integer.compare(x, y)
	}
}


二、函数型接口

Java8 内置的四大核心函数接口

1、Consumer: 消费型接口
void accept(T t)

应用实例:

@Test
public void test1(){
	consumer(100, m -> System.out.println("一共消费"+m+"元"));
}
public void consumer(double money, Consumer<Double> consumer){
	consumer.accept(money);
}

2、Supplier:供给型接口
T get()

应用实例

@Test
public void test(){
	List<Integer> list = get(10, () -> (int)(Math.random()*100));
	for(Integer n : list){
		System.out.println(n);
	}
}
public List<Integer> get(int num, Supplier<Integer> sup){
	List<Integer> list = new ArrayList<>();
	for(int i = 0;i < num; i++){
		int n = sup.get();
		list.add(n);
	}
	return list;
}

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

应用实例:

@Test
public void test3(){
	String s = handle("       hahahaha", (str) -> str.trim());
	System.out.println(s);
	String s2 = handle("hello", (str) -> str.substring(2,4));
}
public String handle(String str, Function<String, String> fun){
	return fun.apply(str);
}

4、Predicate:断言型接口
boolean test(T t)

应用实例:

@Test
public void test(){
	List<String> list = Arrays.asList("hello","world","wo","ni");
	List<String> newList = filter(list, (str).length() > 3);
	for(String s : new List){
		System.out.println(s);
	}
}

public List<String> filter(List<String> list, Predicate<String> pre){
	List<String> strList = new ArrayList();
	for(String s : list){
		if(pre.test(s)){
			strList.add(s);
		}
	}
	return strList;
}


三、Stream 流

3.1 Stream 三个步骤

  1. 创建Stream
    一个数据源(如:集合,数组)获取一个流
  2. 中间操作
    一个中间操作链,对数据源的数据进行处理
  3. 终止操作(终端操作)
    一个终止操作,执行中间操作链,并产生结果
    在这里插入图片描述

3.2 Stream 中间操作

多个中间操作可以连续起来形成一个流水线,除非流水线上发出终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为"惰性求值"
在这里插入图片描述
这里我们首先建立一个员工实体类,然后创建对象,实例操作中会用到。实体类略。

// 创建匿名对象
List<Employee> emp = Arrays.asList(
       new Employee(101, "张三",18, 9999),
       new Employee(102, "李四",48, 6666),
       new Employee(103, "五张",28, 333),
       new Employee(104, "赵六",8, 777),
       new Employee(106, "赵八",28, 45777),
       new Employee(106, "赵八",28, 45777),
       new Employee(107, "赵九",8, 7767),
       new Employee(105, "老七",38, 5555)
);

3.2.1 filter

接收 Lambda,从流中排序某些元素

实例演示:找出上面年龄大于30岁的员工

@Test
public void test(){
	Stream<Employee> stream = emp.stream()
		.filter(e -> e.getAge() > 30);
	stream.forEach(System.out::println);
}
// 另一种写法
public void test(){
	Stream<Employee> stream = emp.stream()
		.filter(e -> {
			return e.getAge() > 30;
		});
	stream.forEach(System.out::println);
}
/*
	结果:
	Employee{no=102, name='李四', age=48, sal=6666, Status=null}
	Employee{no=105, name='老七', age=38, sal=5555, Status=null}
*/

3.2.2 limit(n) 截断流使其元素不超过给定数量

实例演示: 找出工资大于3000 的前 n 位
limit 不牵扯排序,只是创建对象的先后顺序

public void test(){
	Stream<Integer> limit = emp.stream()
		.filter(e -> e.getSal() > 3000)
		.map(Employee::getSal)
		.limit(3);
	limit.forEach(System.out::println);
}
/*
	结果:
		9999
		6666
		45777
*/

3.2.3 skip(n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流,与 limit(n) 互补

public void test(){
	emp.stream()
		.filter(e -> e.getSal() > 3000)
		.map(Employee::getName)
		.skip(2)
		.forEach(System.out::println);
}
/*
	结果:
		赵八
		赵九
		老七
*/

3.2.4 筛选,去重,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

实例演示:找出 薪水 大于9000的前两位,并去重复

public void test(){
	emp.stream()
		.filter(e -> e.getSal() > 9000)
		.skip(2)
		.distinct()
		.forEach(System.out::println);
}
/*
	结果:
		Employee{no=106, name='赵八', age=28, sal=45777, Status=null}
*/

3.3 映射

map —— 接收 Lambda ,将元素转化成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatMap —— 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

案例操作:将 小写字母转换成大写字母并输出

public void test(){
	list<String> list = Arrays.asList("aa","b","cc","dd","ee");
	list.stream()
		.map(str -> str.toUpperCase())
		.forEach(System.out::println);
}
/*
	结果:
		AA
		BB
		CC
		DD
*/

// 将员工的姓名以map形式输出
emp.stream
	.map(Employee::getName)
	.forEach(System.out::println);
// 将 list 集合中的字母 单个输出 使用 flatMap
Stream<Character> stream = list.stream()
	.flatMap(TestStreamAPI(类名) :: filtercharacter(方法名));
stream.forEach(System.out::println);
/*
	结果:
		五张
		赵六
		赵八
		赵八
		赵九
		老七
*/

// 静态方法 
public static Stream<Character> filterCharacter(String str){
	List<Character> list = new ArrayList<>();
	// toCharArray() 方法将字符串转换为字符数组
	for(character ch : str.toCharArray()){
		list.add(ch);
	}
	return list.stream();
}
/*
	结果:
		aabbccdd
*/

3.4 排序 sorted()

案例演示:将 List 中字符串按首字母排序

public void test(){
	List<String> list = Arrays.asList("ccc","aaa","bbb","ddd","eee");
	list.stream
		.sorted()
		.forEach(System.out::println);
}
/*
	结果:
		aaa
		bbb
		ccc
		ddd
		eee
*/


四、查找与匹配

allMatch —— 检查是否匹配所有元素
anyMatch —— 检查是否至少匹配一个元素
noneMatch —— 检查是否没有匹配所有元素
findFirst —— 返回第一个元素
findAny —— 返回当前流中的任意元素
count —— 返回流中元素的总个数
max —— 返回流中最大值
min —— 返回流中最小值

创建 员工对象,额外加一个员工状态

List<Employee> emp = Arrays.asList(
      new Employee(101, "张三",18, 9999, Employee.Status.FREE),
      new Employee(102, "李四",48, 6666, Employee.Status.BUSY),
      new Employee(103, "五张",28, 333, Employee.Status.VOCATION),
      new Employee(104, "赵六",8, 777, Employee.Status.FREE),
      new Employee(105, "老七",38, 5555, Employee.Status.BUSY),
      new Employee(105, "老七",38, 5555, Employee.Status.BUSY)
);

案例实操

// allMatch  检查是否匹配所有元素
boolean b = emp.stream()
	.allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
// anyMatch  检查是否至少匹配一个元素
boolean b1 = emp.stream()
	.anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
// noneMatch   检查是否没有匹配所有元素
boolean b2 = emp.stream()
	.noneMatch(e -> e.getStatus).equals(Employee.Status.BUSY));
System.out.println(b2);
//findFirst   返回第一个元素
Optional<Employee> op = emp.stream()
	.sorted((e1, e2) -> Double.compare(e1.getSal(),e2.getSal()))
	.findFirst();
System.out.println(op.get());
//findAny   返回当前流中的任意元素
Optional<Employee> op2 = emp.parallelStream()
	.filter(e -> e.getStatus().equals(Employee.Status.BUSY))
	.findAny();
System.out.println(op2.get());
/*
	结果:
		false
		true
		false
		Employee{no=103, name='五张', age=28, sal=333, Status=VOCATION}
		Employee{no=105, name='老七', age=38, sal=5555, Status=BUSY}
*/

count,max,min

long count = emp.stream()
	.count();
System.out.println(count);
Optional<Employee> op = emp.stream().max((e1, e2) -> Double.compare(e1.getSal(), e2.getSal()));
System.out.println(op.get());
Opotional<Integer> op2 = emp.stream()
	// 先将工资提出来
	.map(Employee::getSal)
	.min(Double::compare);
System.out.println(op2.get());
/*
	结果:
		6
		Employee{no=101, name='张三', age=18, sal=9999, Status=FREE}
		333
*/

五、归约

reduce:可以将流中反复结合起来,得到一个值

public void test(){
	List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
	Integer sum = list.stream()
		// reduce 中第一个参数表示 初始值为多少, 也可以不写第一个参数,默认是 0
		.reduce(0, (x, y) -> x + y);
	System.out.println(sum);

	Optional<integer> reduce = emp.stream()
		.map(Employee::getSal)
		.reduce(Integer::sum);
	System.out.println(reduce.get());
}
/*
	结果:
		55
		28885
*/

六、收集 —— collect

将流转换为其他形式。接受一个 Collector 接口的实现,用于给 Stream 中元素做汇总的方法

==练习一:==集合形式 List,Set,HashSet

List<String> list = emp.stream()
	.map(Employee::getName)
	// List
	.collect(collectors.toList());
list.forEach(System.out::println);

Set<String> set = emp.stream()
	.map(Employee::getName)
	// Set
	.collect(Collectors.toSet());
set.forEach(System.out::println);

HashSet<String> hashSet hashSet = emp.stream()
	.map(Employee::getName)
	// HashSet
	.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);

练习二:总数量,平均值,求和,最大值,最小值

// 总数量
Long count = emp.stream()
	.collect(Collectors.count());
System.out.println(count);
// 平均值: 获取员工薪水的平均值
Double avlSal = emp.stream()
	.collect(Collectors.averageingInt(Employee::getSal));
System.out.println(avlSal);
// 求和:求出所有员工的薪水
int sum = emp.stream()
	.collect(Collectors.summingInt(Employee::getSal));
System.out.println(sum);
// 最大值:获取薪水最高的员工
Optional<Employee> max = emp.stream()
	.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getSal(), e2.getSal())));
System.out.println(max);
// 最小值:只获取数值,不获取其他的信息
Optional<Employee> min = emp.stream()
	.map(Employee::getSal)
	.collect(Collects.minBy(Integer::compare);
System.out.println(min.get());

练习三: 分组:根据员工的状态分组

@Test
public void test6(){
	Map<Employee.Status, List<Employee>> map = emp.stream()
		.collect(Collectors.groupingBy(Employee::getStatus));
	System.out.println(map);
}

练习四: summarizingInt:按照 int 类型来统计
统计 最大值,求和,平均值 薪水

IntSummaryStatistics collect = emp.stream()
	.collect(Collectors.summarizingInt(Employee::getSal));
System.out.println(collect.getMax());
System.out.println(collect.getMin());
System.out.println(collect.getAverage());


小结:

以上是学习完Java8新特性之后,比较常用的东西,还差一些知识点,不够完整,这些应该是比较常用的。在写的过程中可能会感觉到像写 SQL 语句有一些类似,多多练习,方能熟练掌握。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值