一、Lambda
Lambda表达式体现的是函数式编程思想,只需要把执行的代码放到函数中(函数就是类中的方法),Lambda是一个匿名含函数,秩序将要执行的代码放到Lambda表达式中即可。一般看到方法的参数是接口的优先考虑用Lambda,可以想象成Lambda表达式是对接口中抽象方法的重写。
好处:可以简化匿名内部类,减少代码冗余,让代码更加精简。
public class LambdaTest {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Runnable内部处理");
}
}).start();
new Thread(() -> System.out.println("Lambda内部处理")).start();
}
}
实现原理:
运行时会发现并没有产生一个新的class文件,可以使用jdk自带的工具javap,进行对字节码的反汇编,来进行查看实现原理。如下:
cmd-> javap -c -p 文件名.class
注:-c:表示对代码进行反汇编;-p:显示所有类的成员
private static void lambda$main$0();
Code:
0: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #9 // String Lambda内部处理
5: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
还可以通过:
java -Djdk.internal.lambda.dumpProxyClasses.包名.class类名。生成运行时class文件
匿名内部类在编译的时候会生成一个class文件,可以看到Lambda其实也是生成了一个匿名内部类,这个类也会实现这个接口,并实现接口的抽象方法。
final class LambdaTest$$Lambda$1
implements Runnable
{
public void run()
{
LambdaTest.lambda$main$0();
}
private LambdaTest$$Lambda$1()
{
}
Lambda在程序运行的时候形成一个类
1.会在类中新增一个方法,这个方法体就是一个Lambda表达式中的代码
2.形成一个匿名内部类,实现接口重写抽象方法
3.在接口的重写方法中会调用新生成的方法
4.方法的参数或局部变量类型必须为接口才能使用Lambda
5.接口中有且只能有一个抽象方法,否则Lambda不知道重写哪个方法。jdk8推出检测接口方法个数的注解,可避免开发中的疏忽:
常见引用方式 |
---|
对象::方法名 |
类名::静态方法 |
类名::普通方法 |
类名::new调用的构造器 |
String[]::new调用数组构造器 |
小结:
当接口中只有一个抽象方法时,建议使用Lambda表达式,其他情况还是需要使用匿名内部类。
二、Stream
1.Stream获取方式
方式一:根据Conllection获取流(Conllection接口中有一个默认方法:stream())
List<String> list = new ArrayList<>();
//List方式
List<String> list = new ArrayList<>();
Stream<String> stream3 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream4 = set.stream();
//Map方式
Map<String,String> map = new HashMap<>();
Stream<String> stream = map.keySet().stream();
Stream<String> stream1 = map.values().stream();
Stream<Map.Entry<String, String>> stream2 = map.entrySet().stream();
方式二:Stream中的静态of方法获取流
Stream<String> stringStream = Stream.of("a", "b", "c");
2.Stream常用方法
方法名 | 方法作用 | 返回值类型 |
---|---|---|
count | 统计个数 | long |
forEach | 循环 | void |
filter | 过滤 | Stream |
limit | 取前几个 | Stream |
skip | 取后几个 | Stream |
map | 映射 | Stream |
concat | 组合 | Stream |
3.常用方法实例Demo
①生成流
- stream() - 为集合创建串行流
- parallelStream() − 为集合创建并行流
②forEach
//遍历10个随机数
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
③filter
//按条件遍历不为空的字符串:[abc, bc, efg, abcd, jkl]
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
strings.stream().filter(s -> StringUtils.isNotEmpty(s)).collect(Collectors.toList());
④map
//输出数字的平方:[1, 4, 9, 16, 25, 36, 49, 64, 81]
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
list.stream().map(i -> i * i).collect(Collectors.toList());
⑤limit
//获取指定数量的流
Random random1 = new Random();
random1.ints().limit(2).forEach(System.out::println);
⑥sorted
//将指定数量流排序
Random random2 = new Random();
random2.ints().limit(10).sorted().forEach(System.out::println);
⑦collectors
//流转换集合和聚合元素,也可以返回列表/字符串
List<String> strings1 = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings1.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings1.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
注意:
①Stream只能操作一次
②Stream方法返回的是新流
③Stream不调用终结方法,中间的操作不会执行
三、Optional
1.使用方法
①定义Optional两种方式
Optional<String> str = Optional.of("cx");
Optional<String> empty = Optional.empty();
②配合Lambda应用场景(如:获取bean中姓名,并转换大写操作输出)
public static void main(String[] args) {
User user = new User("Hello", 12);
Optional<User> hello = Optional.of(user);
System.out.println(getUpp(hello));
}
/**
* 先遍历出姓名字段,将姓名字段转换大写,最后添加判断否则为null操作。
*/
public static String getUpp(Optional<User> user) {
return user.map(User::getUserName).map(String::toUpperCase).orElse("null");
}
public static class User {
private String userName;
private Integer age;
public User(String userName, Integer age) {
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}