文章目录
前言
优化简洁的开发Java 8新特性 Lambda 表达式
一、Lambda 是什么?
Lambda 是Jdk 1.8 的一种新特性。
优点:
- 速度更快
- 代码更少
- 强大的 Stream API
- 便于并行
- 最大减少空指针异常 Optical
二、基本语法
//1.无参无返回Lambda 表达式
Runnable run = () -> System.out.println("Hello Lambda");
run.run();
//2.有一个参数无返回值 Lambda 表达式语法 无返回值可以去掉大括号
Consumer<String> consumer = e -> System.out.println(e);
consumer.accept("Hello Lambda!");
//有参数有返回值 Lambda 表达式语法 多条语句操作
Comparator<Integer> comparator = (x, y) -> {
System.out.printf("函数式接口!");
return Integer.compare(x,y);
};
comparator.compare(0,1);
//3.有参数有返回值 Lambda 表达式语法 只有一条语句的话 返回和大括号都可以去掉
//Lambda 表达式参数列表的数据类型可以不要写,因为JVM 根据编译器可以推断出来
Comparator<Integer> comparator1 = (x, y) -> Integer.compare(x,y);
comparator1.compare(0,1);
//Lambda 需要函数式接口的支持 函数式接口? 函数式接口是只有一个抽象方法的接口
//使用注解 @FunctionalInterface 修饰指定是函数方法
//使用函数式接口实现运算
System.out.println(operation(100,(x)-> x + 900));
/**
*
* @param num
* @param myFun 函数式接口
* @return
*/
public Integer operation(Integer num,MyFun myFun){
return myFun.getValue(num);
}
三、自己练习深刻理解使用
List<Employee> employees = Arrays.asList(new Employee(1,30,4444.00,"小强")
,new Employee(2,16,9999.00,"小唐")
,new Employee(3,18,7777.00,"小李")
,new Employee(4,14,6666.00,"小心")
,new Employee(5,26,5555.00,"比尔鸭"));
/**
* Lambda 使用
* 调用Collections.sort(); 定制排序先按年龄比,年龄相同按姓名比
*/
@Test
public void LambdaSort(){
Collections.sort(employees,(x,y)->{
if (x.getAge()==y.getAge()) {
return x.getName().compareTo(y.getName());
}else {
return - x.getAge().compareTo(y.getAge());
}
});
for (Employee emp: employees) {
System.out.println(emp);
}
}
![定制排序先按年龄比,年龄相同按姓名比结果](https://img-blog.csdnimg.cn/af91bbbfd530460eb8317c422438c82b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaWRlYeS4tg==,size_20,color_FFFFFF,t_70,g_se,x_16)
/**
* Lambda 使用 自定义函数式接口
* 实现字符串操作
*/
@Test
public void strHandlerTest(){
//去除空格
System.out.println(strHandler("\t\t\t小",(str)-> str.trim()));
//转换大写 一个参数一个返回可以省去括号
System.out.println(strHandler("abcdefg",str -> str.toUpperCase(Locale.ROOT)));
//转换小写
System.out.println(strHandler("ABCDEFG",str -> str.toLowerCase(Locale.ROOT)));
//截取
System.out.println(strHandler("ABCDEFG",str -> str.substring(0,4)));
}
/**
* 用于处理字符串
* @param str 字符串
* @param myFunction 函数式接口
* @return
*/
public String strHandler(String str,MyFunction myFunction){
return myFunction.getValue(str);
}
/**
* Lambda 泛型自定义函数接口计算
*/
@Test
public void opCalculation(){
//加
op(100L,200L,(x,y)->x+y);
//减
op(100L,200L,(x,y)->x-y);
//乘
op(100L,200L,(x,y)->x*y);
}
/**
*
* @param l1
* @param l2
* @param myFunction 自定义函数接口
*/
public void op(Long l1,Long l2,MyFunction1<Long,Long> myFunction){
System.out.println(myFunction.getValue(l1,l2));
}
四、java 8 四大内置核心函数式接口
Consumer<T>
消费型接口
/**
* Lambda 调用 消费型接口
*/
@Test
public void happyTest(){
happy(2000.00,m-> System.out.println("今天我买了个Switch花了"+m+"元"));
}
/**
* 消费型 接口使用
* @param money
* @param consumer
*/
public void happy(Double money,Consumer<Double> consumer){
consumer.accept(money);
}
Supplier<T>
供给型接口 主要方法 T get();
/**
* Lambda 调用 供给型接口
*/
@Test
public void numListTest(){
List<Integer> numList = getNumList(10,()->(int)(Math.random() * 100));
for (Integer num: numList){
System.out.println(num);
}
}
/**
* 供给型接口 接口使用 指定生成多少个数放入集合中
* @param num
* @param supplier
* @return
*/
public List<Integer> getNumList(Integer num,Supplier<Integer> supplier){
List<Integer> numList = new ArrayList<>();
for (int i = 0; i < num; i++) {
numList.add(supplier.get());
}
return numList;
}
Predicate<T>
段言型接口 用于做判断操作的 主要方法 boolean test(T t);
/**
* java 8 段言型接口
* @return
*/
@Test
public void nameLengthCheckTest(){
List<Employee> nameList = nameLengthCheck(employees,(x)->x.getName().length()<3);
for (Employee employee:nameList) {
System.out.println(employee);
}
}
/**
* java 8 段言型接口 把名字长度小于三的都取出来
* @param employees 集合
* @return
*/
public List<Employee> nameLengthCheck(List<Employee> employees,Predicate<Employee> predicate{
List<Employee> nameList = new ArrayList<>();
for (Employee emp:employees){
if (predicate.test(emp)){
nameList.add(emp);
}
}
return nameList;
}
函数型接口 主要方法 R apply(T t);
/**
* Lambda 使用
* 实现字符串操作
*/
@Test
public void strHandlerTests(){
//去除空格
System.out.println(strHandlers("\t\t\t小",(str)-> str.trim()));
//转换大写 一个参数一个返回可以省去括号
System.out.println(strHandlers("abcdefg",str -> str.toUpperCase(Locale.ROOT)));
//转换小写
System.out.println(strHandlers("ABCDEFG",str -> str.toLowerCase(Locale.ROOT)));
//截取
System.out.println(strHandlers("ABCDEFG",str -> str.substring(0,4)));
}
/**
* java 8 提供函数式接口 Function
* @param str 字符串
* @param function 函数式接口
* @return
*/
public String strHandlers(String str,Function<String, String> function){
return function.apply(str);
}
总结
左右遇一括号省
左侧推断类型省
能省则省
五、java 8 新特性方法引用与构造器引用
方法引用:若方法体中的内容已经有方法实现了,那么我们可以使用方法引用
/**
* 注意:
* 1.Lambda 体中调用参数类型与返回值类型要与函数式接口抽象方法参数列表返回值类型一致
* 2.若Lambda 参数列表第一个参数是调用者,第二个是该实例方法的参数时可以使用 语法3: 类::实例方法名
*/
@Test
public void test1(){
/**
* 方法引用
*/
//语法1: 对象::实例方法名
PrintStream printStream = System.out;
Consumer<String> consumer = printStream::println;
consumer.accept("对象::实例方法名");
//语法2: 类::静态方法名
Comparator<Integer> comparator = Integer::compare;
//语法3: 类::实例方法名
BiPredicate<String,String> predicate =String::equals;
System.out.println(predicate.test("小","小"));
/**
* 构造器引用 语法: 类::new
* 注意: 掉用实例类构造器取决于函数式接口的参数列表来决定
*/
Supplier<Employee> supplier = Employee::new;
System.out.println(supplier.get());
//自定义函数式接口
MyFunction2<Integer,Integer> myFunction2 = Employee::new;
/**
* 数组引用 语法: Type[]::new
*/
Function<Integer,String[]> function = String[]::new;
System.out.println(function.apply(20).length);
}
六、java 8 新特性 Stream API
1. Stream API 描述
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是StreamAPI(java.util.stream.*)
。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对、集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
2. 流(Stream)到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储光素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
3. Stream 操作的三个步骤
1.创建 Stream
一个数据源(如:集合、数组),获取一个流
2.中间操作
一个中间操作链,对数据源的数据进行处理•终止操作(终端操作)
3.终止操作
一个终止操作,执行中间操作链,并产生结果
/**
* 创建 Stream
* 1. 可以通过 Collection 系列集合
* 2. 可以通过 Arrays 中的 stream() 创建
* 3. 通过 Stream 的of()方法 创建流
* 4. 创建无限流
*/
// 通过 Collection 系列集合创建
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// 通过Arrays 创建数组流
String[] strings = new String[10] ;
Stream<String> stream2 = Arrays.stream(strings);
// 通过 Stream 的of()方法 创建流
Stream<List<String>> stream3 = Stream.of(list);
//创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0,(x)->x+2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(()->employees).limit(5).forEach(System.out::println);
4. Stream 中间操作
5. Stream 筛选与切片
List<Employee> employees = Arrays.asList(
new Employee(1,30,9999.00,"小强")
,new Employee(2,16,9999.00,"小唐")
,new Employee(3,18,7777.00,"小李")
,new Employee(4,14,6666.00,"小心")
,new Employee(2,16,9999.00,"小唐")
,new Employee(2,16,9999.00,"小唐")
,new Employee(2,16,9999.00,"小唐")
,new Employee(5,26,5555.00,"比尔鸭"));
/**
* 筛选与切片
* filter—接收 Lambda ,从流中排除某些元素。
* limit—截颧流,使其元素不超过给定数量。
* skip(n)—跳过元素,返回一个扔掉了前 n 个元素的流。
* 若流中元素不足 n 个,则返回一个空流。
* 与ljmit(n)互补distinct—筛选,通过流所生成元素的 hashCode()和 equals()去除重复元素
*/
//内部迭代: 迭代 操作 由Stream API 完成
@Test
public void testFilter(){
employees.stream().filter(e->{
//中间操作: 不执行任何操作
System.out.println("StreamAPI 中间操作!");
return e.getAge()>18;
//终止操作 一次性执行全部内容 "称为惰性求值"
}).forEach(System.out::println);
}
@Test
public void testLimit(){
employees.stream()
.filter(employee -> {
//中间操作: 不执行任何操作
System.out.println("StreamAPI 中间操作!");
return employee.getSalary()>5000;
}).limit(1)
//终止操作 一次性执行全部内容 "称为惰性求值"
.forEach(System.out::println);
}
@Test
public void testSkip(){
employees.stream()
.filter(employee -> {
//中间操作: 不执行任何操作
System.out.println("StreamAPI 中间操作!");
return employee.getSalary()>5000;
}).skip(2)
//终止操作 一次性执行全部内容 "称为惰性求值"
.forEach(System.out::println);
}
@Test
public void testDistinct(){
employees.stream()
.filter(employee -> {
//中间操作: 不执行任何操作
System.out.println("StreamAPI 中间操作!");
return employee.getSalary()>5000;
}).limit(10)
.distinct()
//终止操作 一次性执行全部内容 "称为惰性求值"
.forEach(System.out::println);
}
6. Stream 映射
/**
* 映射
* map—接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
* flatMap—接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
@Test
public void testMap(){
List<String> stringList = Arrays.asList("aaa","bbb","ccc");
employees
.stream()
.map(Employee::getName)
.forEach(System.out::println);
stringList
.stream()
.map(str->str.toUpperCase(Locale.ROOT))
.forEach(System.out::println);
}
@Test
public void testFlatMap(){
List<String> stringList = Arrays.asList("aaa","bbb","ccc");
//-------------------Map-----------------
stringList
.stream()
.map(TestStreamAPI1::filterCharacter)
.forEach(em->{
em.forEach(System.out::println);
});
//-------------------FlatMap-----------------
//flatMap—接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
stringList
.stream()
.flatMap(TestStreamAPI1::filterCharacter)
.forEach(System.out::println);
}
/**
* 提取单个字符
* @param str 字符串
* @return
*/
public static Stream<Character> filterCharacter(String str){
List<Character> stringList = new ArrayList<>();
for (Character character:str.toCharArray()){
stringList.add(character);
}
return stringList.stream();
}
7. Stream 排序
/**
* 排序
* sorted() 自然排序 Comparable
* sorted(Comparator com) 定制排序 Comparator
*/
@Test
public void testSort(){
List<Integer> list = Arrays.asList(1,3,2,5,4);
//-------------------sorted() 自然排序 Comparable-----------------
list.stream()
.sorted()
.forEach(System.out::println);
//-------------------sorted(Comparator com) 定制排序 Comparator-----------------
employees.stream()
.sorted((x,y)->{
if (x.getAge().equals(y.getAge())){
return x.getName().compareTo(y.getName());
}else{
return x.getAge().compareTo(y.getAge());
}
})
.forEach(System.out::println);
}
8. Stream 终止操作 查找与匹配
/**
* 查找与匹配
* allMatch—检查是否匹配所有元素
* anyMatch—检查是否至少匹配一个元素
* noneMatch—检查是否没有匹配所有元素
* findFirst—返回第一个元素
* findAny—返回当前流中的任意元素
* count—返回流中元素的总个数
* max—返回流中最大值
* min—返回流中最小值
*/
@Test
public void test(){
//--------------allMatch----------------
boolean b1 = employees.stream()
.allMatch(employee -> employee.getName().equals("小唐"));
System.out.println(b1);
//--------------anyMatch----------------
boolean b2 = employees.stream()
.anyMatch(employee -> employee.getSalary()>1000);
System.out.println(b2);
//--------------noneMatch----------------
boolean b3 = employees.stream()
.anyMatch(employee -> employee.getName().equals("小唐"));
System.out.println(b3);
//--------------noneMatch----------------
Optional<Employee> o = employees.stream()
.sorted((x,y)-> -Double.compare(x.getSalary(),y.getSalary()))
.findFirst();
System.out.println(o.get());
//--------------findAny----------------
Optional o1 = employees.parallelStream()
.filter(employee -> employee.getAge()>18)
.findAny();
System.out.println(o1.get());
//--------------count----------------
long log = employees.stream().count();
System.out.println(log);
//--------------max----------------
Optional salaryMax = employees.stream().max((x,y)->Double.compare(x.getSalary(),y.getSalary()));
System.out.println(salaryMax);
//--------------min----------------
Optional salaryMin = employees.stream()
.min((x,y)-> Double.compare(x.getSalary(),y.getSalary()));
System.out.println(salaryMin);
}
9. Stream 终止操作 规约与收集
/**
* 规约
* reduce 一个流中的元素反复结合起来,得到一个值
* 收集
* collect 将流转换成其他形式。接受一个Collector 接口实现,用于给Stream 元素做汇总
*/
@Test
public void test(){
//-----------------规约------------------
Optional<Double> o = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(o.get());
//-----------------收集------------------
employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet())
.forEach(System.out::println);
employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new))
.forEach(System.out::println);
employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(LinkedHashSet::new))
.forEach(System.out::println);
//-----------------收集获取工资平均值------------------
Double ave = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(ave);
}