前言
b站java课程学习笔记整理。
b站视频: 黑马程序员全套Java教程_Java基础入门视频教程,零基础小白自学Java必备教程
355. 体验Lambda表达式
函数式编程思想:
尽量忽略面向对象的复杂语法,强调做什么,而不是以什么形式去做。
示例:
1 2 3 4 5 6 7 8 9 10
| package LambdaDemo;
public class Demo { public static void main(String[] args) { new Thread(() -> { System.out.println("启动"); }).start(); } }
|
356. Lambda表达式的标准格式
1 2 3 4 5 6 7 8 9
| package LambdaDemo;
public class Demo { public static void main(String[] args) { new Thread(() -> { System.out.println("启动"); }).start(); } }
|
Lambda表达式的代码分析
- ():里面没有内容,可以看成是方法形式参数为空
- ->:用箭头指向后面要做的事
- {}:包含一段代码,我们成为代码块,可以看成是方法体中的内容。
三要素:形参,箭头,代码块。
- Lambda表达式的格式:
(形式参数)->{代码块}
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可。
- ->:固定写法,代表指向动作。
- 代码块: 具体要做的事,也就是以前我们写的方法体的内容。
357. Lambda表达式的练习1(抽象方法无参无返回值)
使用前提:
1 2 3 4 5 6 7 8 9
| package Lambda练习1;
public class EatableImpl implements Eatable{ @Override public void eat() { System.out.println("吃吃吃"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package Lambda练习1;
public class Demo { public static void main(String[] args) { Eatable e = new EatableImpl(); useEatable(e); useEatable(()->{ System.out.println("吃饭"); }); } private static void useEatable(Eatable e){ e.eat(); } }
|
358. Lambda表达式的练习2(抽象方法带参无返回值)
1 2 3 4 5 6
| package Lambda练习2;
public interface Flyable { void fly(String s); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package Lambda练习2;
public class FlyDemo { public static void main(String[] args) { useFlyable((String s) ->{ System.out.println(s); System.out.println("飞机自驾游"); }); } private static void useFlyable(Flyable f){ f.fly("风和日丽"); }
}
|
359. Lambda表达式的练习3(抽象方法带参带返回值)
1 2 3 4 5 6
| package Lambda练习3;
public interface Addable { int add(int x, int y); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package Lambda练习3;
public class AddDemo { public static void main(String[] args) { useAddable((int x, int y) -> { return x-y; }); }
public static void useAddable(Addable a) { int sum = a.add(10, 20); System.out.println(sum); } }
|
360. Lambda表达式的省略模式
- 参数类型可以省略。但是有多个参数的情况下不能只省略一个。
- 如果参数有且仅有一个,那么小括号可以省略。
- 如果代码块的语句只有一条,可以省略大括号和分号,甚至return。
361. Lambda表达式的注意事项
- 使用Lambda一定要有接口,并且接口中有且仅有一个抽象方法。
- 必须有上下文环境。
- 根据局部变量的赋值
Runnable r =() ->System.out.println("Lambda表达式");
- 根据调用方法的参数
new Thread(()->System.out.println("lambda表达式")).start();
362. Lambda表达式和匿名内部类的区别
所需类型不同
- 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类。
- Lambda表达式:只能是接口
使用限制不同
- 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类。
- 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
实现原理不同
- 匿名内部类:编译后,产生一个单独的.class字节码文件。
- Lambda:编译后没有.class文件。对应的字节码会在运行时动态生成。
363. 接口组成更新
接口的组成
- 常量
- 抽象方法
- 默认方法(Java 8)
- 静态方法(Java 8)
- 私有方法(Java 9)
364. 接口中的默认方法
java中提供的更新接口的默认方法default
。添加默认方法时不会强制让实现类重写这个方法(不过也可以重写)。
示例:
1 2 3
| default void show3(){ System.out.println("show3"); }
|
365. 接口中静态方法
使用static
关键字修饰。
只能同故宫接口名去调用。和static
的成员方法类似。public
可以省略
例子:
1 2 3
| static void test(){ System.out.println("静态方法") }
|
366. 接口中私有方法
- 格式1:
private 返回值类型 方法名(参数列表){}
范例1:private void show(){}
- 格式2:
private static 返回值类型 方法名(参数列表){}
范例2:private static void method(){}
可以是普通的私有方法,也可以是静态的私有方法。
私有方法是用来将接口中的各种方法的共同点抽象出来,简化代码的书写。
注意事项:
- 默认方法可以调用私有的静态方法和非静态方法。
- 静态方法只能调用私有的静态方法
367. 方法引用
通过方法引用来使用已经存在的方案。
方法引用符:::
1 2 3 4 5 6 7 8 9 10 11 12 13
| package Lambda练习2;
public class FlyDemo { public static void main(String[] args) { useFlyable(System.out::println); } private static void useFlyable(Flyable f){ f.fly("风和日丽"); }
}
|
原则: 可推导的就是可省略的。
368. 方法引用符
::
该符号位引用运算符,他所在的表达式称为方法引用。
- 可推导的就是可省略的。
- 方法引用是Lambda的孪生兄弟
1 2 3 4 5 6
| package 方法引用符;
public interface Printable { void printInt(int i); }
|
1 2 3 4 5 6 7 8 9 10 11
| package 方法引用符;
public class Demo { public static void main(String[] args) { usePrintable(System.out::println); }
public static void usePrintable(Printable p){ p.printInt(666); } }
|
369. 引用类方法
引用类方法,其实就是引用类的静态方法。
- 格式:
类名::静态方法
- 范例:
Integer::parseInt
370. 引用对象的实例方法
格式:对象::成员方法
范例:"Hello world"::toUpperCase
371. 引用类的实例方法
格式:类名::成员方法
范例:String :: substring
372. 引用构造器
其实就是引用构造方法。
格式:类名::new
范例:Student::new
373. 函数式接口
有且仅有一个抽象方法的接口。(即lambda表达式的使用前提)
如何检测一个接口是不是函数式接口?
@FunctionalInterface
用来检查。就类似于@Override
374. 函数式接口作为方法的参数
如果方法的参数是一个函数式接口,可以使用Lambda表达式作为参数传递。
startThread(()->System.out.println(Thread.currentThread().getName()+"启动"));
375. 函数式接口作为方法的返回值
如果方法的返回值是一个函数式接口,可以使用Lambda表达式作为结果返回
1 2 3
| private static Comparator<String>getComparator(){ return (s1,s2)->s1.length - s2.length(); }
|
376.函数式接口之supplier
Supplier<T>
:包含一个无参的方法。
T get()
: 获得结果
- 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
Supplier<T>
接口也被称为生产型接口,如果制定了泛型是什么类型,那么接口中的get方法就会产生什么类型的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package supplier使用;
import java.util.function.Supplier;
public class Demo { public static void main(String[] args) { String s = getString(()-> "林青霞"); System.out.println(s); } private static String getString(Supplier<String> sup){ return sup.get(); } }
|
377. supplier接口之获取最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package supplier使用;
import java.util.function.Supplier;
public class Demo { public static void main(String[] args) { int[] arr = {1, 2, 23, 5, 6}; int maxValue = getMax(() -> { int max = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } return max; }); System.out.println(maxValue); }
public static int getMax(Supplier<Integer> sup) { return sup.get();
} }
|
378. Consumer接口
Consumer<T>
:包含两个方法。
void accept(T t)
: 对给定的参数执行此操作
default Consumer <T> andThen(Consumer after)
:返回一个组合的Consumer
,依次执行此操作,然后执行after
操作。
Consumer<T>
接口也被称为消费型接口。
1 2 3 4 5 6 7 8 9 10 11 12 13
| package Consumer接口;
import java.util.function.Consumer;
public class Demo { public static void main(String[] args) { operatorString("dasdsa", System.out::println, s-> System.out.println(new StringBuilder(s).reverse())); } private static void operatorString(String name, Consumer<String> con1,Consumer<String> con2){ con1.andThen(con2).accept(name); } }
|
消费就是对数据执行一次操作。
379. 练习:按要求打印信息
String[] strArray = {"林青霞,30","张曼玉,35","王祖贤,33"};
- 按照姓名:XX,年龄:XX的格式把信息打印出来。
- 要求:
- 把打印姓名的动作作为第一个Consumer接口的Lambda实例。
- 把打印年龄的动作作为第二个Consumer接口的Lambda实例。
- 将两个Consumer几口按照顺序组合到一起使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package Consumer接口;
import java.util.function.Consumer;
public class Demo2 { public static void main(String[] args) { String[] strArray = {"林青霞,30","张曼玉,35","王祖贤,33"};
printInfo(strArray,str -> System.out.print("姓名:"+str.split(",")[0]),str-> System.out.println(",年龄"+Integer.parseInt(str.split(",")[1]))); } private static void printInfo(String[] strArray, Consumer<String> con1,Consumer<String> con2){ for(String str : strArray){ con1.andThen(con2).accept(str); } } }
|
380. predicate接口1
Consumer<T>
:常用四个方法。
boolean test(T t)
:对给定的参数进行判断,判断逻辑由Lambda表达式实现,返回一个布尔值。
default Predicate<T> negate()
: 返回一个逻辑的否定,对应逻辑非。
default Predicate<T> and(Predicate other)
:返回一个短路与的组合判断。
default Predicate<T>or(Predicate other)
:返回一个组合判断,对应短路或。
Predicate<T>
接口通常用于判断参数是否满足指定的条件。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package PredicateDemo;
import java.util.function.Predicate;
public class Demo { public static void main(String[] args) { boolean b1 = checkString("hello",s-> s.length()>8); System.out.println(b1); } private static boolean checkString(String s, Predicate<String> pre){ return pre.test(s); } }
|
381. predicate接口2
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package PredicateDemo;
import java.util.function.Predicate;
public class Demo { public static void main(String[] args) { boolean b1 = checkString("helloworld",s-> s.length()>8,s->s.length()<15); System.out.println(b1); } private static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2){ return pre1.and(pre2).test(s); } }
|
382. 练习:筛选满足条件的数据
-
String[] strArray = {"林青霞,30","柳岩,34","张曼玉,35","貂蝉,31","王祖贤,33"};
-
使用predicate
接口,将符号要求的字符串筛选到集合ArrayList
中。
-
同时满足以下要求: 姓名长度大于2,年龄大于33
-
分析:
使用and方法连接判断条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package predicate应用;
import java.util.ArrayList; import java.util.function.Predicate;
public class Demo { public static void main(String[] args) { String[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"}; ArrayList<String> list = myFilter(strArray, s -> s.split(",")[0].length() > 2, s -> Integer.parseInt(s.split(",")[1]) > 33); for(String str:list){ System.out.println(str); } }
public static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2) { ArrayList<String> array = new ArrayList<>(); for (String str : strArray) { if (pre1.and(pre2).test(str)) { array.add(str); } } return array; } }
|
383. Function接口
Function<T,R>
:常用两个方法。
R apply(T t)
将此函数应用于给定的参数
default <V> Function andThen(Function after)
:返回一个组合函数,首先将该函数应用于输入,然后将after
函数应用于结果。
384. Function接口的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package predicate应用;
import java.util.function.Function;
public class Demo { public static void main(String[] args) { String s = "林青霞,33"; convert(s,name->name.split(",")[1], Integer::parseInt,i->i+70); } private static void convert(String s, Function<String, String>fun1,Function<String, Integer>fun2,Function<Integer, Integer>fun3){ int i = fun1.andThen(fun2).andThen(fun3).apply(s); System.out.println(i); } }
|