Java8新特性

一、Lambda表达式
-
Lambda 是一个匿名函数,我们可以把Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
- 格式:
- lambda操作符或箭头操作符
- 左边:lambda形参列表(其实就是借口中的抽象方法的形参列表)
- 右边:lambda体(其实就是重写的抽象方法的方法体)
- lambda表达式的本质:作为接口的实例
lambda表达式举例:
- 语法格式一:无参,无返回值
1 public class Test02 { 2 int num = 10; //jdk 1.7以前 必须final修饰 3 4 @Test 5 public void test01(){ 6 //匿名内部类 7 new Runnable() { 8 @Override 9 public void run() { 10 //在局部类中引用同级局部变量 11 //只读 12 System.out.println("Hello World" + num); 13 } 14 }; 15 } 16 17 @Test 18 public void test02(){ 19 //lambda表达式 20 Runnable runnable = () -> { 21 System.out.println("Hello Lambda,我是run()函数"); 22 }; 23 } 24 }
- 语法格式二 :有一个参数,没有返回值
- 语法格式三:若只有一个参数,小括号可以省略不写 a -> System.out.println(a)
- 语法格式四:数据类型可以省略不写,由JVM编译器通过上下文推断得出
1 @Test 2 public void test03(){ 3 Consumer<String> consumer = (a) -> System.out.println(a); 4 consumer.accept("我省略了accept函数名!"); 5 }
- 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
1 @Test 2 public void test04(){ 3 Comparator<Integer> comparator = (a, b) -> { 4 System.out.println("比较接口"); 5 return Integer.compare(a, b); 6 }; 7 }
- 语法格式六:当若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
1 Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
二、函数式接口
- 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
java内置四大核心函数式接口
- 消费型接口
1 /** 2 * Consumer<T> 消费型接口 : 3 */ 4 @Test 5 public void consumerTest() { 6 happy(2999.99, m -> System.out.println("此次消费了:" + m + "元")); 7 } 8 9 public void happy(Double money, Consumer<Double> consumer) { 10 consumer.accept(money); 11 }
- 提供型接口
1 /** 2 * Supplier<T> 供给型接口 : 3 */ 4 @Test 5 public void supplierTest() { 6 Random random = new Random(); 7 List<Integer> numList = getNumList(10, () -> random.nextInt(100)); 8 numList.forEach(System.out::println); 9 } 10 11 /** 12 * 需求:产生指定个数的整数,并放入集合中 13 * 14 * @param num 15 * @param sup 16 * @return 17 */ 18 public List<Integer> getNumList(int num, Supplier<Integer> sup) { 19 List<Integer> list = new ArrayList<>(); 20 21 for (int i = 0; i < num; i++) { 22 Integer n = sup.get(); 23 list.add(n); 24 } 25 26 return list; 27 }
- 函数型接口
1 /** 2 * Function<T, R> 函数型接口 3 */ 4 @Test 5 public void functionTest() { 6 // s -> s.trim() 可替换成 String::trim 7 String newStr = strHandler("\t\t\t 威武 ", s -> s.trim()); 8 System.out.println(newStr); 9 10 String subStr = strHandler(" 威武呀", s -> s.substring(2, 5)); 11 System.out.println(subStr); 12 } 13 14 /** 15 * 需求:用于处理字符串 16 * 17 * @param str 18 * @param fun 19 * @return 20 */ 21 public String strHandler(String str, Function<String, String> fun) { 22 return fun.apply(str); 23 }
- 断言型接口
1 /** 2 * Predicate<T> 断言型接口: 3 */ 4 @Test 5 public void predicateTest(){ 6 List<String> list = Arrays.asList("Hello", "yxj", "Lambda", "www", "ok"); 7 List<String> strings = filterStr(list, p -> p.length() > 3); 8 strings.forEach(System.out::println); 9 } 10 11 /** 12 * 需求:将满足条件的字符串,放入集合中 13 * 14 * @param list 15 * @param pre 16 * @return 17 */ 18 public List<String> filterStr(List<String> list, Predicate<String> pre) { 19 List<String> strList = new ArrayList<>(); 20 21 for (String str : list) { 22 if (pre.test(str)) { 23 strList.add(str); 24 } 25 } 26 27 return strList; 28 }
三、方法引用和构造器引用
(1)
1.方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
2.方法引用本质上就是lambda表达式
3.使用格式: 类(或对象) ::方法名
4.具体分为如下三种情况:
对象 ::非静态方法
类::静态方法
类::非静态方法
①:
1 /** 2 * 对象::实例方法 3 */ 4 @Test 5 public void test01() { 6 PrintStream printStream = System.out; 7 Consumer<String> consumer = s -> printStream.println(s); 8 consumer.accept("aaa"); 9 10 Consumer<String> consumer2 = printStream::println; 11 consumer2.accept("bbb"); 12 } 13 14 @Test 15 public void test02(){ 16 Employee emp = new Employee(101, "张三", 18, 9999.99); 17 Supplier<String> supplier = ()->emp.getName(); 18 System.out.println(supplier.get()); 19 20 Supplier<String> supplier2 = emp::getName; 21 System.out.println(supplier2.get()); 22 } 23 24 @Test 25 public void test03(){ 26 BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y); 27 Double apply = fun.apply(99.99, 199.99); 28 System.out.println(apply); 29 30 BiFunction<Double, Double, Double> fun2 = Math::max; 31 Double apply1 = fun2.apply(88.88, 188.88); 32 System.out.println(apply1); 33 }
②
1 /** 2 * 类名 :: 静态方法名 3 */ 4 @Test 5 public void test02() { 6 Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b); 7 System.out.println(comparator.compare(1, 2)); 8 9 Comparator<Integer> comparator2 = Integer::compare; 10 System.out.println(comparator2.compare(10, 20)); 11 }
③
1 /** 2 * 类名 :: 实例方法名 3 */ 4 @Test 5 public void test05() { 6 BiPredicate<String, String> bp = (x, y) -> x.equals(y); 7 boolean test = bp.test("hello word", "hello future"); 8 9 BiPredicate<String, String> bp2 = String::equals; 10 boolean test2 = bp2.test("hello word", "hello future"); 11 12 System.out.println("-----------------------------------------"); 13 14 Function<Employee, String> function = e -> e.show(); 15 String apply = function.apply(new Employee()); 16 System.out.println(apply); 17 18 Function<Employee, String> function2 = Employee::show; 19 String apply1 = function2.apply(new Employee()); 20 System.out.println(apply1); 21 }
(2)构造器引用
1 /** 2 * 构造器引用 3 */ 4 @Test 5 public void test06() { 6 Supplier<Employee> supplier = () -> new Employee(); 7 Employee employee = supplier.get(); 8 System.out.println(employee); 9 10 Supplier<Employee> supplier1 = Employee::new; 11 Employee employee1 = supplier1.get(); 12 System.out.println(employee1); 13 } 14 15 @Test 16 public void test07(){ 17 Supplier<List> supplier = ()->new ArrayList<Integer>(); 18 List list = supplier.get(); 19 list.add(1); 20 list.add(2); 21 System.out.println(list); 22 23 Supplier<List> supplier1 = ArrayList::new; 24 List list1 = supplier1.get(); 25 System.out.println(list1); 26 }
(3)数组引用
1 /** 2 * 数组引用 3 */ 4 @Test 5 public void test08(){ 6 Function<Integer, String[]> fun = (args)->new String[args]; 7 String[] apply = fun.apply(10); 8 System.out.println("apply.length = " + apply.length); 9 10 System.out.println("--------------------------"); 11 12 Function<Integer, Employee[]> fun2 = Employee[]::new; 13 Employee[] apply1 = fun2.apply(20); 14 System.out.println("apply1.length = " + apply1.length); 15 }
四、Stream API
注意:产生一个全新的流,和原来的数据源没有关系(数据源不受影响)!!!
Stream 的操作三个步骤
- 创建 Stream
- 一个数据源(如:集合、数组),获取一个流
- 中间操作
- 一个中间操作链,对数据源的数据进行处理
- 终止操作(终端操作)
- 一个终止操作,执行中间操作链,并产生结果
①Stream的创建(实例化)
1 /** 2 * 创建流 3 */ 4 @Test 5 public void test01(){ 6 /** 7 * 方式一:集合流 8 * - Collection.stream() 串行流 9 * - Collection.parallelStream() 并行流 10 */ 11 List<String> list = new ArrayList<>(); 12 Stream<String> stream1 = list.stream(); 13 14 //方式二:数组流 15 //Arrays.stream(array) 16 String[] strings = new String[10]; 17 Stream<String> stream2 = Arrays.stream(strings); 18 19 //方式三:Stream 静态方法 20 //Stream.of(...) 21 Stream<Integer> stream3 = Stream.of(1, 2, 3); 22 23 //方式四:无限流(了解) 24 //迭代 25 Stream<Integer> stream4 = Stream.iterate(0, (i) -> i+2); 26 stream4.forEach(System.out::println); 27 28 //生成 29 Stream.generate(() -> Math.random()) 30 .limit(5) 31 .forEach(System.out::println); 32 }
②Stream的中间操作
filter:筛选与切片
1 //2. 中间操作 2 List<Employee> emps = Arrays.asList( 3 new Employee(102, "李四", 59, 6666.66), 4 new Employee(101, "张三", 18, 9999.99), 5 new Employee(103, "王五", 28, 3333.33), 6 new Employee(104, "赵六", 8, 7777.77), 7 new Employee(104, "赵六", 8, 7777.77), 8 new Employee(104, "赵六", 8, 7777.77), 9 new Employee(105, "田七", 38, 5555.55) 10 ); 11 12 //内部迭代:迭代操作 Stream API 内部完成 13 @Test 14 public void test2(){ 15 //所有的中间操作不会做任何的处理 16 Stream<Employee> stream = emps.stream() 17 .filter((e) -> { 18 System.out.println("测试中间操作"); 19 // 加 return 原因:因为lambda表达式中,如果有多条语句,需要用大括号括起来,最后一句为返回语句,要加return 20 return e.getAge() <= 35; 21 }); 22 23 //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值” 24 stream.forEach(System.out::println); 25 } 26 27 //外部迭代 28 @Test 29 public void test3(){ 30 Iterator<Employee> it = emps.iterator(); 31 32 while(it.hasNext()){ 33 System.out.println(it.next()); 34 } 35 }
limit:截断流
1 @Test 2 public void test4(){ 3 emps.stream() 4 .filter((e) -> { 5 System.out.println("短路!"); // && || 6 return e.getSalary() >= 5000; 7 }).limit(3) 8 .forEach(System.out::println); 9 }
skip(n):跳过元素
1 @Test 2 public void test5() { 3 emps.parallelStream() 4 .filter((e) -> e.getSalary() >= 5000) 5 .skip(2) 6 .forEach(System.out::println); 7 }
distinct:筛选
1 @Test 2 public void test6() { 3 emps.stream() 4 .distinct() 5 .forEach(System.out::println); 6 }
需要重写hashCode()和equals()方法
映射:

排序:

(3)Stream的终止操作
查找/匹配

归约
收集
1 /** 2 * 把员工的名字收集到指定的集合中 3 */ 4 @Test 5 public void test08(){ 6 List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList()); 7 list.forEach(System.out::println); 8 9 System.out.println("--------------"); 10 11 Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet()); 12 set.forEach(System.out::println); 13 14 System.out.println("--------------"); 15 16 Map<Long, String> collect = emps.stream().collect(Collectors.toMap(Employee::getId, Employee::getName)); 17 System.out.println(collect); 18 }
五、Optional类
Optional 类 (java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在用 Optional 可以更好的表达这个概念;并且可以避免空指针异常
- Optional.of(T t):创建一个 Optional 实例
- Optional.empty(T t):创建一个空的 Optional 实例
- Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则空实例
- isPresent():判断是否包含某值
- orElse(T t):如果调用对象包含值,返回该值,否则返回 t
- orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值
- map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
- flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional
1 @Test 2 public void test01(){ 3 Optional<Employee> employee = Optional.of(new Employee()); 4 System.out.println(employee.get()); 5 6 System.out.println("=========="); 7 8 Optional<Object> o = Optional.of(null); 9 System.out.println(o.get()); 10 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)