在现在的企业级开发中, 随着新技术的迭代, 越来越多的公司开始使用Java8的新特性去简化开发, 因此Java8非常值得我们学习. 在学习Java8的时候, 我们需要了解一下Java8都有哪些主要的新特性
而在企业开发中, 主要用到的便是Lambda表达式和Stream流 , 而在下面,我们便主要的去学习这两方面的知识
Lambda表达式本质上是一个匿名函数, 可以简单理解为一个可以将代码像数据一样传递的代码 特点: 简洁, 灵活
基本语法
在写lambda表达式时, 只需关注函数和方法体即可
参数: 写在小括号中
方法体: 写在大括号内
->: lambda表达式运算符, 分隔参数和方法体
注意:
举例:
定义了三个接口, 利用lambda去实现相关功能
/** * Author TimePause * Create 2020-05-03 22:03 */ public interface SingleReturnMultipleParameter { int test(int a,int b); } /** * Author TimePause * Create 2020-05-03 22:04 */ public interface NoneReturnParmarter { void test(); } /** * Author TimePause * Create 2020-05-03 22:26 */ public interface SingleReturnSingleParameter { int test(int x); } /** * lambda表达式: 对接口进行简洁的实现 * * @author TimePause * @create 2020-05-03 22:05 */ public class TestLambda { public static void main(String[] args) { //测试lambda无返回值无参 NoneReturnParmarter lambda1= ()-> { System.out.println("lambda-NoneReturnParmarter"); }; lambda1.test(); //测试lambda单个返回值多个参数 SingleReturnMultipleParameter lambda2=(int a,int b)->{ return a + b; }; System.out.println(lambda2.test(1, 2)); //测试lambda单个参数单个返回值 SingleReturnSingleParameter lambda3=(int x)->{ return x*x; }; System.out.println(lambda3.test(3)); //测试lambda单个/多个参数省略参数类型 SingleReturnMultipleParameter lambda5=(a,b)->{ return a + b; }; System.out.println(lambda5.test(1, 2)); //测试lambda单个参数省略小括号(两个无法省略) SingleReturnSingleParameter lambda6= x->{return x*x; }; /** * 注意: * 1.如果方法体中代码只有一行,那么大括号可以省略 * 2.如果唯一的一行代码是返回语句,那么在大括号省略的同时, 返回值也必须省略 */ NoneReturnParmarter lambda7= ()-> System.out.println("lambda-NoneReturnParmarter"); SingleReturnSingleParameter lambda8= x-> x*x; } }
lambda表达式的函数引用
举例:
使用上面实现过的接口来实现引用
/** * Author TimePause * Create 2020-05-03 22:03 */ public interface SingleReturnMultipleParameter { int test(int a,int b); } /** * 测试lambda表达式的引用 * * @author TimePause * @create 2020-05-04 22:11 */ public class TestLambda2 { public static void main(String[] args) { //测试lambda表达式的引用: 类名::方法名 SingleReturnMultipleParameter lambda=TestLambda2::getAbs; lambda.test(2, 3); //相当于下面的方式 SingleReturnMultipleParameter lambda1 = (a, b) -> TestLambda2.getAbs(a, b); System.out.println(lambda1.test(2, 3)); //测试对非静态方法的引用 NoneReturnParmarter lambda2=new TestLambda2()::show; lambda2.test(); } /** * 引用注意: * 1.把私有修饰符去掉以后可在其他类中通过 类名::方法名引用其他方法 * 2.如果是静态方法引用方式为: 类名::方法名 * 如果是非静态方法引用方式为: 对象::方法名 */ static int getAbs(int a,int b){ return a>b?a-b:b-a; } public void show(){ System.out.println("如果是非静态方法引用方式为: 对象::方法名"); } }
lambda表达式对构造方法的引用
lambda在引用时,会根据接口类型不同自动适配是带参还是无参的构造方法!!!
/** * 测试lambda表达式对构造方法的引用 * * @author TimePause * @create 2020-05-04 22:38 */ public class TestLambda3 { public static void main(String[] args) { //lambda在引用时,会根据接口类型不同自动适配是带参还是无参的构造方法!!! PersonMake lambda1=Person::new; PersonMake2 lambda2 = Person::new; } } //定义一个实体类两个接口, 分别测试lambda对带参和无参方法的引用 class Person{ String name; int age; Person(){} Person(String name,int age){ this.name = name; this.age = age; } } interface PersonMake{ Person getPerson(); } interface PersonMake2{ Person getPerson(String name,int age); }
lambda表达式对get(),set()方法的引用
引用时需要根据接口进行适配
public class TestLambda3 { public static void main(String[] args) { //对get方法的引用 getName lambda4=Person::getName; //对set方法的引用 setName lambda5=new Person()::setName; } } class Person{ String name; int age; public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } interface getName{ String get(Person p); } interface setName{ void set(String name); }
lambda简单应用1
/** * 测试lambda表达式实现数组的降序排序 * * @author TimePause * @create 2020-05-05 9:24 */ public class TestLambda4 { public static void main(String[] args) { Integer arr[] = {1, 9, 8, 3, 5, 6}; //ctrl+f12=>查看当前类下所有方法 Arrays.sort(arr);//这是正序 System.out.println(Arrays.toString(arr)); Arrays.sort(arr,(x,y)-> y-x);//这是倒序 System.out.println(Arrays.toString(arr)); } }
简单应用2
将上面的TestLambda3 代码进行修改,可以测试lambda对对象数组的某个属性进行排序的情况
public class TestLambda3 { public static void main(String[] args) { Person[] persons=new Person[5]; persons[0] = new Person("小1", 33); persons[1] = new Person("小2", 21); persons[2] = new Person("小3", 25); persons[3] = new Person("小4", 28); persons[4] = new Person("小5", 19); //利用lambda对其按照年龄进行正序排序 Arrays.sort(persons,(p1,p2)->p1.getAge()-p2.getAge()); for (int i = 0; i < persons.length; i++) { System.out.println(persons[i]); } } } //定义一个实体类两个接口, 分别测试lambda对带参和无参方法的引用 class Person{ String name; int age; Person(){} Person(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
在对集合中的元素进行操作的时候, 有时候可能会用到其他结果, 在这个过程中使用集合的流式编程可以简化代码量, 将数据源中的数据读取到一个流中, 可以对这个流进行操作(删除, 过滤, 映射…)
介绍
Stream流是对集合操作的增强, 它不是一种数据结构,也不负责存储. 更像一个迭代器,且单向遍历不可循环
实现步骤
注意:
数据源就是数据的来源, 从数据源中读取到流中 需要注意的是对流中数据的操作(删除, 映射, 过滤…)是不会影响数据源的数据的
/** * 测试Stream流式编程获取数据源 * * @author TimePause * @create 2020-05-05 11:34 */ public class TestStream { public static void main(String[] args) { List<Object> list = new ArrayList<>(); /** * 数据源的获取 * 1.stream获取的数据源是串行的 * 2.parallelStream获取的数据源是并行的, 且该方法封装了多线程对数据的操作, 效率更高 */ list.stream(); list.parallelStream(); //Stream获取数组元素 int[] arr={1,9,8,0,2,3}; IntStream stream = Arrays.stream(arr); } }
最终操作指的是将流中的数据整合在一起, 放入一个集合, 也可以直接对流中的数据进行遍历统计, 提取出我们想要的信息 注意: 在使用最终操作后会关闭这个流并销毁流中的数据, 如果再次使用这个已关闭的流则会出现异常
/** * 测试最终操作 * * @author TimePause * @create 2020-05-05 12:09 */ public class TestStream2 { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); Collections.addAll(list, 5, 10, 15, 20, 25); /** * 1.collect: * 通过在collect()方法内调用Collectors的其他方法,将流中的数据转化成其他类型的数据 */ //将最终结果转成list List<Integer> collect = list.stream().collect(Collectors.toList()); System.out.println(collect); //将最终结果转成set Set<Integer> set = list.stream().collect(Collectors.toSet()); System.out.println(set); //将最终结果转成map Map<Integer, Integer> map = list.stream().collect(Collectors.toMap(e -> e / 5, e -> e)); System.out.println(map); /** * 2.reduce:将流中的所有元素带入这个方法中进行运算 * 最终的运算结果是一个optional类型的数据,需要调用get()方法获取其中的数据 */ int res = list.stream().reduce((e1, e2) -> e1 + e2).get(); System.out.println(res); /** * 3.count:统计流中的数据的个数 */ long count = list.stream().count(); System.out.println(count); /** * 4.foreach:遍历流中的元素 */ list.stream().forEach(System.out::println); /** * 5.max&min: 获取流中的最大值和最小值 */ Integer max = list.stream().max(Integer::compareTo).get(); System.out.println("集合中的最大值是: "+max); Integer min = list.stream().min(Integer::compareTo).get(); System.out.println("集合中的最小值是: "+min); /** * 6.allMatch & anyMatch & noneMatch=>matching * allMatch: 只有流中所有元素都满足匹配规则,才返回true * anyMatch: 只要有任意一个元素满足匹配规则,就返回true * noneMatch: 只有流中所有的元素都不满足匹配规则,才返回true */ boolean allMatch = list.stream().allMatch(e -> e > 20); System.out.println(allMatch); boolean anyMatch = list.stream().anyMatch(e -> e > 20); System.out.println(anyMatch); boolean noneMatch = list.stream().noneMatch(e -> e %5 !=0); System.out.println(noneMatch); /** * 7.find: 查找流中的第一个元素 * findFirst()和findAny()在绝大多数情况下作用是一样的, 只有在多线程的环境下才可能不同 */ Integer findFirst = list.parallelStream().findFirst().get(); Integer findAny = list.parallelStream().findAny().get(); System.out.println(findFirst +"---"+findAny); /** * 注意事项:在使用最终操作后会关闭这个流并销毁流中的数据, 如果再次使用这个已关闭的流则会出现异常 * 异常打印如下: * Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed * at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229) * at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:464) */ Stream<Integer> stream = list.stream(); long count1 = stream.count(); System.out.println(count1); Integer integer = stream.findFirst().get(); System.out.println(integer); } }
中间操作指的是对流中的数据做各式各样的处理, 中间操作可以是连续的操作, 每次操作都返回一个Stream对象, 直到最终操作的执行
/** * 测试Stream的中间操作(对数组,集合进行操作) * * @author TimePause * @create 2020-05-05 15:45 */ public class TestStream3 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "hello", "world", "hello", "TimePause", "csdn"); /** * 1.filter:过滤流中符合条件的元素 */ list.stream().filter(e->e.length()>5).forEach(System.out::println); /** * 2.distinct: 去除集合中重复的元素 * 这个方法没有参数, 去重规则与hashset相同(会比较hashcode,如果hashcode相同会比较equals,equals相同则认为相同则去重) */ list.stream().distinct().forEach(System.out::println); /** * 3.sorted: 排序 * sorted():默认是按照流中的元素对应的类,实现的comparable接口中的方法进行排序 * 也可以在()内将流中的数据按照指定的规则进行排序 */ list.stream().sorted().forEach(System.out::println); list.stream().sorted((e1,e2)->e1.length()-e2.length()).forEach(System.out::println); /** * 4.skip & limit (这两个方法一般会联合使用) * skip(): 跳过指定个数的元素 * limit():截取指定个数的元素 */ list.stream().skip(2).forEach(System.out::println); list.stream().limit(2).forEach(System.out::println); //如何获取 hello TimePause? list.stream().skip(2).limit(2).forEach(System.out::println); /** * 5. map & flatMap (重要!!!) * map: 对流中的数据进行映射,用新的数据替换旧的数据 * flatMap: 也是元素的映射,不过是扁平化的映射, 将容器中所有元素取出放到集合中 */ list.stream().map(e->e+".txt").forEach(System.out::println); String[] strs = {"hello world", "hello csdn", "hello TimePause", "hello csdn"}; //数组也可以使用Stream Arrays.stream(strs).map(String::toCharArray).forEach(e-> System.out.println(Arrays.toString(e))); Arrays.stream(strs).map(e->e.split(" ")).flatMap(Arrays::stream).forEach(System.out::println); //strs->map(arrays)->flatMap(elements) } }
/** * 测试Stream中间操作之maptoint (对对象组成的集合进行操作) * * @author TimePause * @create 2020-05-05 20:58 */ public class TestStream4 { public static void main(String[] args) { ArrayList<Persons> person = new ArrayList<>(); Collections.addAll(person,new Persons("小a",14),new Persons("小b",12),new Persons("小c",33)); //Integer sum = person.stream().map(e -> e.getAge()).reduce((e1, e2) -> e1 + e2).get(); //System.out.println(sum); /** * maptoInt: 将流中的数据转成int,此时这个方法的返回值不再是Stream * 此时这个方法的返回值不再是Stream而是IntStream */ double average = person.stream().mapToInt(Persons::getAge).average().getAsDouble();//获取平均年龄 System.out.println(average); } } class Persons{ String name; int age; public Persons(String name, int age) { this.name = name; this.age = age; } public int getAge() { return age; } }
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * 综合练习 * * @author TimePause * @create 2020-05-05 21:27 */ public class TestStream5 { public static void main(String[] args) { ArrayList<Student> studentList = new ArrayList<>(); Collections.addAll(studentList, new Student("小1",59), new Student("小2",99), new Student("小3",87), new Student("小4",68), new Student("小5",71) ); //1.求出所有及格的学生 System.out.println("---------------1.求出所有及格的学生--------------"); studentList. stream(). filter(e->e.getScore()>60). forEach(System.out::println); //2.求出所有及格的学生的姓名 System.out.println("---------------2.求出所有及格的学生的姓名--------------"); studentList. stream(). filter(e->e.getScore()>60). map(Student::getName). forEach(System.out::println); //3.求出所有学生的平均成绩 System.out.println("---------------3.求出所有学生的平均成绩--------------"); double averageScore = studentList. stream(). mapToInt(Student::getScore). average().getAsDouble(); System.out.println(averageScore); //4.求班级前三名(做成集合)??? System.out.println("---------------4.求班级前三名(做成集合)--------------"); List<Student> collect = studentList. stream(). sorted((e1, e2) -> e2.getScore() - e1.getScore()). limit(3). collect(Collectors.toList()); collect.forEach(System.out::println); //5.求班级的3-10名(做成集合) System.out.println("---------------5.求班级的3-10名(做成集合)--------------"); List<Student> collect2 = studentList. stream(). sorted((e1, e2) -> e2.getScore() - e1.getScore()). limit(10). skip(2). collect(Collectors.toList()); collect2.forEach(System.out::println); //6.求所有不及格学生的平均成绩 System.out.println("---------------6.求所有不及格学生的平均成绩--------------"); double averageScore2 = studentList. stream(). filter(e -> e.getScore() < 60). mapToInt(e -> e.getScore()). average(). getAsDouble(); System.out.println(averageScore2); //7.将及格的学生, 按照成绩降序输出所有信息 System.out.println("---------------7.将及格的学生, 按照成绩降序输出所有信息--------------"); studentList. stream(). filter(e->e.getScore()>60). sorted((e1,e2)->e2.getScore()-e1.getScore()). forEach(System.out::println); //8.班级学生的总分=>从这里可以看出很多时候e->e.getScore()可以替换Student::getScore,都是对get()方法的引用 System.out.println("---------------8.班级学生的总分--------------"); int res = studentList.stream().mapToInt(Student::getScore).reduce((e1, e2) -> e1 + e2).getAsInt(); int res2 = studentList.stream().mapToInt(e->e.getScore()).reduce((e1, e2) -> e1 + e2).getAsInt(); int res3 = studentList.stream().mapToInt(e -> e.getScore()).sum(); System.out.println(res); System.out.println(res2); System.out.println(res3); } } class Student{ private String name; private int score; public Student(String name,int score ){ this.name=name; this.score = score; } public String getName(){ return name; } public int getScore(){ return score; } @Override public String toString() { return String.format("姓名: %s, 成绩: %d", name, score); } }
聪明的人能够看到本文配套学习视频哦: https://www.bilibili.com/video/BV1N7411v796?p=1
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句