JDK8新特性——Lambda
1.Lambda表达式
特殊的匿名内部类,语法更加简洁。
Lambda表达式允许把函数作为一个方法的参数传递,将代码像数据一样传递。
1.1基本语法:
<函数式接口><变量名>=(参数1,参数2,...)->{
//方法体
}
函数式接口是被注解@FunctionalInterface标注的接口:
如下是一个自定义的函数式接口:
package com.jzt.lambda;
/**
* 自定义一个函数式接口
*/
@FunctionalInterface
public interface IUsb {
void work();
}
1.2操作符
Lambda表达式引入了新的操作符:->(箭头操作符),->将表达式分为两个部分:
-
左侧:(参数1,参数2…)标识参数列表
-
右侧:{}内部是方法体。
1.3注意事项
- 形参列表的数据类型会自动推断;
- 如果形参列表为空,只需要写()即可;
- 如果形参只有一个,()可以省略,只需要参数的名称即可
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省略{},则需要同时省略return,且执行语句也必须保证只有一句。
- Lambda表达式不会生成单独的内部类文件。
1.3举例
package com.jzt.lambda;
import java.util.Comparator;
import java.util.TreeSet;
/**
* 演示Lambda表达式
*/
public class Demo1 {
public static void main(String[] args) {
Runnable runnable = new Runnable(){
@Override
public void run() {
System.out.println("子线程运行了");
}
};
new Thread(runnable).start();
//使用Lambda表达式来简化
Runnable runnable2 = ()->System.out.println("子线程运行了");
new Thread(()->System.out.println("子线程运行了")).start();
//例子2Comparator比较器
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
TreeSet<String> treeSet = new TreeSet<>(comparator);
//使用Lambda表达式简化
Comparator<String> comparator2 = (o1, o2)->o1.length() - o2.length();
TreeSet<String> treeSet2 = new TreeSet<>(comparator2);
}
}
2.函数式接口
2.1概述
如果一个接口只有一个抽象方法,则该接口称作为函数式接口。
函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
通过**@FunctionalInterface**注解可以检测一个接口是否为函数式接口。
package com.jzt.lambda;
@FunctionalInterface
public interface IUsb {
void work();
}package com.jzt.lambda; @FunctionalInterface public interface IUsb { void work(); }
2.2常见的函数式接口
函数式接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Consumer消费型接口 | T | void | void accept(T t);对象类型为T的对象应用操作 |
Supplier供给型接口 | 无 | T | T get();返回类型为T的对象 |
Function<T,R>函数型接口 | T | R | R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象 |
Predicate断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。 |
2.3函数式接口的使用
2.3.1消费型接口
package com.jzt.lambda;
import java.util.function.Consumer;
/**
* 演示函数式接口的使用1
* 消费型接口
*/
public class Demo3 {
public static void main(String[] args) {
//使用匿名内部类
Consumer<Double> consumer = new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("消费了:"+aDouble);
}
};
shopping(consumer,1000.0);
//使用Lambda表达式
Consumer<Double> consumer1 = aDouble->System.out.println("消费了:"+aDouble);
shopping(consumer1, 2000.0);
shopping(aDouble->System.out.println("消费了:"+aDouble), 3000.0);
}
//Consumer消费型接口
public static void shopping(Consumer<Double> consumer, Double money){
consumer.accept(money);
}
}
2.3.2供给型接口
package com.jzt.lambda;
import java.util.Arrays;
import java.util.Random;
import java.util.function.Supplier;
/**
* 供给型接口演示
*/
public class Demo4 {
public static void main(String[] args) {
//使用匿名内部类的方式
Supplier<Integer> supplier = new Supplier<Integer>() {
@Override
public Integer get() {
return new Random().nextInt(100);
}
};
int[] result = getNums(supplier, 5);
System.out.println(Arrays.toString(result));
//使用Lamdba表达式
Supplier<Integer> supplier2 = () -> new Random().nextInt(100);
int[] result2 = getNums(supplier2, 10);
System.out.println(Arrays.toString(result2));
//在简化
int[] result3 = getNums(() -> new Random().nextInt(100), 15);
System.out.println(Arrays.toString(result3));
}
public static int[] getNums(Supplier<Integer> supplier, int count){
int[] arr = new int[count];
for(int i = 0; i < count; i++){
arr[i] = supplier.get();
}
return arr;
}
}
2.3.3函数型接口
package com.jzt.lambda;
import java.util.function.Function;
/**
* 函数式接口演示
*/
public class Demo5 {
public static void main(String[] args) {
//匿名内部类的方式
Function<String, String> function = new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();//全部转为大写
}
};
String result = handlerStr(function, "abc");
System.out.println(result);
//使用Lambda表达式
String result2 = handlerStr(s -> s.trim(), " abc ");//去除空格
System.out.println(result2);
}
public static String handlerStr(Function<String, String> function, String str){
return function.apply(str);
}
}
4)断言型接口
package com.jzt.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
/**
* 演示断言型接口
*/
public class Demo6 {
public static void main(String[] args) {
//匿名内部类方式
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("Test");//是否已Test开头
}
};
List<String> list = new ArrayList<>();
list.add("Test_zhangsan");
list.add("tt_lisi");
list.add("Test_wangwu");
list.add("zhaoliu");
List<String> result = filterNames(predicate, list);
System.out.println(result);
//Lambda表达式
List<String> result2 = filterNames(s -> s.contains("t"), list);//是否包含字符串t
System.out.println(result2);
}
public static List<String> filterNames(Predicate<String> predicate, List<String> list){
List<String> strList = new ArrayList<>();
for(String str : list){
if(predicate.test(str)){
strList.add(str);
}
}
return strList;
}
}
3.方法引用
方法引用是Lambda表达式的一种简写形式。如果Lambda表达式中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见的形式:
- 对象::实例方法,表示调用改对象实例方法
- 类::静态方法,表示调用改类的静态方法
- 类::实例方法,表示调用该类实例方法
- 类::new,表示创建该类的一个对象
package com.jzt.lambda;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 演示方法引用
* 1、对象::实例方法
* 2、类::静态方法
* 3、类::实例方法
* 4、类::new
*/
public class Demo7 {
public static void main(String[] args) {
//1、对象::实例方法
Consumer<String> consumer = s -> System.out.println(s);
/*
* 分析:
* 1)Consumer接口只有void accept(T t)方法,
* 2)System.out对象的方法public void println(String x),参数形式与Consumer接口的accept方法一致
*/
//使用方法引用
Consumer<String> consumer1 = System.out::println;
//2、类::静态方法
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
/*
* 分析:
* 1)Comparator接口只有int compare(T o1, T o2);
* 2)Integer类的方法public static int compare(int x, int y),
* 参数形式与Comparator接口的compare方法一致,同时参数列表也是一致的
*/
//使用方法引用
Comparator<Integer> comparator1 = Integer::compare;
//3、类::实例方法
Function<User, String> function = s -> s.getName();
/*
* 分析:
* 1)Function接口只有R apply(T t);
* 2)等号右侧就是就是apply中传入的对象User调用自身的getName()方法,且返回值也是String
*/
//方法引用
Function<User, String> function1 = User::getName;
System.out.println(function1.apply(new User("小明", 18)));
//4、类::new
Supplier<User> supplier = () -> new User();
//方法引用
Supplier<User> supplier2 = User::new;
User user = supplier2.get();
System.out.println(user);
}
}
User类
package com.jzt.lambda;
public class User {
private String name;
private int age;
public User() {
super();
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.Stream流
流(Stream)中保存对集合或数组数据的操作。和集合类似,单机和中保存的是数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJYADxPO-1609056606099)(D:\data\youdaoNote\weixinobU7VjoqKsPIOC3vcNuosN7uJCCM\ac3aa22894e64e709be2ce3576e5013d\clipboard.png)]
4.1Stream特点
- Stream自己不会存储元素;
- Stream不会改变远对象,相反,他们会返回一个持有结果的新Stream。
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4.2Stream使用步骤
1)创建
新建一个流
2)中间操作
在一个或者多个步骤中,将初始化Stream转化到另一个Stream的中间操作
3)终止操作
使用一个种植操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,改Stream就不嗯能够使用了。
4.2.1创建Stream
创建Stream集中方式:
- 通过Collection对象的stream()或者parallelStream()方法;
- 通过Arrays工具类的stream()方法;
- 通过Stream接口的of()、iterate()、fenerate()方法;
- 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
下面演示:
package com.jzt.lambda;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 演示创建Stream的四种方式:
* - 通过Collection对象的stream()或者parallelStream()方法;
* - 通过Arrays工具类的stream()方法;
* - 通过Stream接口的of()、iterate()、fenerate()方法;
* - 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
*/
public class Demo8 {
public static void main(String[] args) {
//1、通过Collection对象的stream()或者parallelStream()方法:
System.out.println("--------------------------------------------");
System.out.println("1、通过Collection对象的stream()或者parallelStream()方法:");
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//1)使用stream()方法
// Stream<String> stream1 = list.stream();
//遍历
// stream1.forEach(s -> System.out.println(s));
//方法引用的方式
// stream1.forEach(System.out::println);
//2)使用parallelStream()方法
Stream<String> stream2 = list.parallelStream();
// stream2.forEach(s -> System.out.println(s));
stream2.forEach(System.out::println);
//2、通过Arrays工具类的stream()方法
System.out.println("--------------------------------------------");
System.out.println("2、通过Arrays工具类的stream()方法");
String[] arr = {"AAA","BBB","CCC"};
Stream<String> stream3 = Arrays.stream(arr);
// stream3.forEach(s -> System.out.println(s));
stream3.forEach(System.out::println);
//3、通过Stream接口的of()、iterate()、fenerate()方法
System.out.println("--------------------------------------------");
System.out.println("3、通过Stream接口的of()、iterate()、fenerate()方法;");
//of方法
Stream<Integer> stream4 = Stream.of(1,2,3,4,5);
// stream4.forEach(s -> System.out.println(s));
stream4.forEach(System.out::println);
//iterate()方法,迭代流
Stream<Integer> stream5 = Stream.iterate(0, x->x+2);
stream5.limit(5).forEach(s-> System.out.println(s));
//fenerate()方法,生成流
Stream<Integer> stream6 = Stream.generate(()-> new Random().nextInt(10));
stream6.limit(10).forEach(System.out::println);
//通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
System.out.println("--------------------------------------------");
System.out.println("通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。");
IntStream stream7 = IntStream.of(100,200,300);
stream7.forEach(System.out::println);
//range()方法
IntStream stream8 = IntStream.range(0, 10);
stream8.forEach(System.out::println);
//rangeClosed()方法
IntStream stream9 = IntStream.rangeClosed(0, 10);
stream9.forEach(System.out::println);
}
}
4.2.2中间操作
-
filter过滤、limit限制、skip跳过、distinct去重、sorted排序
-
map
-
parallel
演示中间操作:
1)filter过滤、limit限制、skip跳过、distinct去重、sorted排序
package com.jzt.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/**
* 演示中间操作
* - filter、limit、skip、distinct、sorted
*/
public class Demo9 {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
list.add(new User("zhangsan", 18));
list.add(new User("lisi", 20));
list.add(new User("wangwu", 22));
list.add(new User("zhaoliu", 19));
list.add(new User("heiqi", 25));
//filter过滤
System.out.println("------------filter---------------");
list.stream()
.filter(e -> e.getAge() >20)
.forEach(System.out::println);
//limit限制
System.out.println("------------limit---------------");
list.stream()
.limit(3)
.forEach(System.out::println);
//skip跳过
System.out.println("------------skip---------------");
list.stream()
.skip(1)
.forEach(System.out::println);
//distinct去重
System.out.println("------------distinct---------------");
//需要User重写equals和hashcode方法
list.add(new User("zhangsan", 18));
list.add(new User("heiqi", 25));
list.stream()
.distinct()
.forEach(System.out::println);
//sorted排序
System.out.println("------------sorted---------------");
list.stream()
.sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()))
.forEach(System.out::println);
}
}
2)map
package com.jzt.lambda;
import java.util.ArrayList;
import java.util.List;
/**
* 演示中间操作
* map 转换为map集合
*/
public class Demo10 {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
list.add(new User("zhangsan", 18));
list.add(new User("lisi", 20));
list.add(new User("wangwu", 22));
list.add(new User("zhaoliu", 19));
list.add(new User("heiqi", 25));
//将list结合转为map
list.stream()
.map(e -> e.getName())
.forEach(System.out::println);
}
}
3)parallel 并行
package com.jzt.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* 演示中间操作
* parallel并行
*/
public class Demo11 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for(int i = 0; i < 10000; i++){
list.add(UUID.randomUUID().toString());
}
//使用串行的方式
long start = System.currentTimeMillis();
long count = list.stream().sorted().count();
long end = System.currentTimeMillis();
System.out.println(end - start);
//使用并行的方式
long start1 = System.currentTimeMillis();
long count1 = list.parallelStream().sorted().count();
long end1 = System.currentTimeMillis();
System.out.println(end1 - start1);
}
}
结果:
time:72
time1:17
4.2.3终止操作
-
forEach遍历、min最小值、max最大值、count计数
-
reduce规约、collect收集
演示操作:
package com.jzt.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 演示终止操作
* - forEach遍历、min最小值、max最大值、count计数
* - reduce规约、collect收集
*/
public class Demo12 {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
list.add(new User("zhangsan", 18));
list.add(new User("lisi", 20));
list.add(new User("wangwu", 22));
list.add(new User("zhaoliu", 19));
list.add(new User("heiqi", 25));
//- forEach遍历、min最小值、max最大值、count计数
//forEach遍历
System.out.println("-----forEach遍历----------------");
list.stream()
.filter(e->{
System.out.println("过滤了");
return e.getAge() > 20;
})
.forEach(System.out::println);
//min最小值
//获取user集合中年龄最小值
System.out.println("-----min最小值----------------");
Optional<User> min = list.stream()
.min((e1, e2)->Integer.compare(e1.getAge(),e2.getAge()));
System.out.println(min.get());
//max最大值
//获取user中年龄最大值
System.out.println("-----max最大值----------------");
Optional<User> max = list.stream()
.max((e1, e2)->Integer.compare(e1.getAge(),e2.getAge()));
System.out.println(max.get());
//count计数
//获取user个数
System.out.println("-----count计数----------------");
long count = list.stream()
.count();
System.out.println(count);
// - reduce规约、collect收集
//reduce规约
//计算所有user年龄和
System.out.println("-----reduce规约----------------");
Optional<Integer> sum = list.stream()
.map(e->e.getAge())
.reduce((x,y)->x+y);
System.out.println(sum.get());
//collect收集
//收集所有user姓名,放入list结合中
System.out.println("-----collect收集----------------");
List<String> names = list.stream()
.map(e->e.getName())
.collect(Collectors.toList());
System.out.println(names);
}
}