Java8新特性目录
一、Lambda表达式
1、Lambda表达式对匿名内部类的优化
注意: Lambda表达式与匿名内部类一样,都 只是定义了 子类或者实现类;在使用时,还 需进行调用 才可
2、Lambda表达式的基本语法(口诀:左右遇一,括号省;左侧推断,类型省)
Lambda表达式使用 ” -> “ 将隐式函数分为两部分;”->“成为箭头操作符(Lambda操作符)
注意: 箭头操作符的左侧是隐式函数的参数列表
箭头操作符的右侧是隐式函数所要执行的功能,即为内容体(Lambda体)
语法格式: (1)无参数、无返回值
() -> System.out.println(“Hello Lambda !!!”);
(2)有一个参数,无返回值
(x) -> System.out.println("Hello " + x + “!!!”);
(3)如果有且只有一个参数,小括号可以省略不写
x -> System.out.println("Hello " + x + “!!!”);
(4)有多个参数,有返回值并且Lambda体有多条语句;Lambda体 必须用大括号
(x, y) -> {
System.out.println("Hello " + (x + y) + “!!!”);
return x + y;
}
(5)如果Lambda体中有且只有一条语句, 大括号和return 都可以省略 不写
(x, y) -> x + y;
(6)Lambda表达式的参数类型可以省略不写,因为JVM编译器会根据上下文去推断出参数的类型;该过程成为“类型推断”。
(若想写,就要全部都写;否则就都不要写)
注意: 上下文的含义 是根据前面 “类名或者接口名 引用” 中的 类名或接口名 跳转到具体类或接口中,再由其中方法的参数类型;来推断Lambda表达式的参数类型。
3、Lambda表达式与函数式接口
注意:Lambda表达式需要函数式接口的支持
函数式接口:接口中只有一个抽象方法的接口,成为“函数式接口”。可以使用注释@FunctionalInterface修饰,来定义函数式接口
// @FunctionalInterface修饰的接口必须是函数式接口,即只能有且仅有一个抽象方法;写多个,@FunctionalInterface会使接口报错
// 可以有多个默认方法和静态方法,前提是默认方法和静态方法里面都有具体的内容;否则@FunctionalInterface会使接口报错:This method requires a body instead of a semicolon
4、lambda表达式实例
public class Java8Tester {
final static String salutation = "Hello! ";
public static void main(String args[]){
GreetingService greetService1 = message ->
System.out.println(salutation + message);
greetService1.sayMessage("Runoob");
//====================相当于下面==============================
GreetingService g = new GreetingService() {
@Override
public void sayMessage(String message) {
System.out.println(salutation + message);
}
};
g.sayMessage("jack");
//===========================================================
}
interface GreetingService {
void sayMessage(String message);
}
}
5、lambda的变量作用域
(1)lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在lambda 内部修改定义在域外的局部变量,否则会编译错误。
也可以直接在lambda 表达式中访问外层的局部变量。
public class Java8Tester {
public static void main(String args[]) {
final int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果为 3
}
public interface Converter<T1, T2> {
void convert(int i);
}
}
(2)lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有final 的语义)
public class Java8Tester {
public static void main(String args[]) {
int num = 1;
Converter<Integer, String> s = (param) ->
System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;
}
public interface Converter<T1, T2> {
void convert(int i);
}
}
//报错信息:Local variable num defined in an enclosing scope must be final or effectively final
把num=5;注释掉就不报错了
(3)在Lambda 表达式当中不允许局部变量与参数同名
public class Java8Tester {
public static void main(String args[]) {
String first = "";
Comparator<String> comparator = (first, second) -> System.out.println(Integer.compare(first.length(),
second.length()));
//编译会出错
comparator.com("aaaaa","bb");
}
public interface Comparator<T> {
void com(String a,String b);
}
}
把String first = "";注掉就不报错了
二 、Stream API
1、Stream(流)的概念
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
注意: 集合讲的是数据,流讲的是计算
2、注意事项
(1)Stream不会自己存储元素
(2)Stream不会改变源对象,而是返回一个持有结果的新Stream
(3)Stream操作是延迟操作,所以Stream是在需要结果的时候才执行的(只有存在终止操作,才会运行中间操作;直到运行到终止操作,才会一次性运行所有中间操作。这种机制成为 惰性求职 )
3、Stream的操作(3个步骤)
(1)创建流对象(创建Stream)
1)通过Collection集合的stream()方法或者parallelStream()进行创建
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
2)通过Arrays数组中的静态stream()方法获取数组流
String[] emps = new String[10];
Stream<String> stream = Arrays.stream(emps);
3)通过Stream类中静态方法of()方法创建流
Stream<String> stream = Stream.of("aa", "bb", "cc");
4)创建无限流(无限:没有下限,一直运行)
//第一种:迭代创建
Stream.iterate(种子, Lambda表达式);
//第二种:生成创建
Stream.generate(Lambda表达式);
(2)中间操作(不会运行)
(3)终止操作(终端操作)
4、Stream操作
(1)筛选与切片:
1)filter(断言型接口):过滤,接收Lambda,从流中排除某些元素;
2)limit(int num):截断流,使其元素不超过给定数量
3)skip(int num):跳过元素,返回一个扔掉前 num 个元素的流;若流中元素不足 num 个,则返回一个空流;与 limit 互补
4)distinct():筛选,通过流所生成的元素的 hashCode() 和 equals() 去除重复元素
注意: 这个筛选是通过hashCode()和equals()进行去重的,需要 重写 hashCode()和equals()
(2)映射:
1)map(函数型接口):将元素转化成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
2)flatMap(函数型接口):接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
(3)排序
1)sorted():自然排序(系统的Comparator 排序方式)
2)sorted(Comparator com):定制排序
5、终止操作
(1)查找与匹配
1)allMatch:检查是否匹配所有元素
2)anyMatch:检查是否至少匹配一个元素
3)noneMatch:检查是否没有匹配所有元素
4)findFirst:返回第一个元素
5)findAny:返回当前流中的任意元素
6)count:返回流中元素的总个数
7)max:返回流中的最大值
8)min:返回流中的最小值
(2)规约
1)reduce(T identity, BinaryOperator):
reduce(BinaryOperator):
可以将流中元素反复结合起来,得到一个值
(3)收集
1)collect(Collectors的方法):将流转换成其他形式。Collector接口的实现,用于给Stream中元素做汇总的方法
三、四大内置核心函数式接口
1、消费型接口(使用参数,不返回;就是消费:有去无回)
接口内容:
Consumer<T>
void accept(T t);
2、供给型接口(不使用参数,却返回;就是供给:)
接口内容:
Supplier<T>
T get();
3、函数型接口(即使用参数,有返回;就是函数)
接口内容:
Function<T, R>
R apply(T t);
4、断言型接口(使用参数,返回boolean;就是断言)
接口内容:
Predicate<T>
boolean test(T t);
四、方法引用
主要有如下 三种 语法格式:
对象::实例方法名
类::静态方法名
类::实例方法名
注意:
(1)Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。
(2)若Lambda参数列表中的第一参数是 实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
五、构造器引用
格式:ClassName :: new
注意: 需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致。