– 其中最重要的就是Lambda表达式和Stream API
Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样可以进行传递)。可以写出灵活、更简洁的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到提升。
/**
* 原来的匿名内部类
*/
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
上面的代码实际上最关键的代码就只有一句:
Integer.compare(o1,o2);
现在有了Lambda表达式就可以这样来写:
/**
* Java8的Lambda表达式就可以解决匿名内部类的问题
*/
@Test
public void test2() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
TreeSet<Integer> ts = new TreeSet<>(com);
}
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!");
}
};
现在我们有了Lambda表达式了,我们就可以这样来写,非常的简便:
Runnable runnable = () -> System.out.println("Hello World");
我们还可以举一个栗子:
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 38, 5555.55),
new Employee("王五", 50, 6666.66),
new Employee("赵六", 16, 3333.33),
new Employee("田七", 8, 7777.77)
);
/** 需求:获取当前公司中员工年龄大于35的员工的信息 */
@Test
public List<Employee> filterEmployees(List<Employee> list) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (emp.getAge() >= 35) {
emps.add(emp);
}
}
return emps;
}
我们对上面的代码进行单元测试,如下图,我们已经对当前公司中员工年龄大于35的员工的信息进行了过滤:
假如这个时候,又来了一个需求:获取当前公司员工工资大于5000的员工的信息,这个时候,我又得重新写个方法,其实我们对比一下方法,要改动的地方就一句,因为这一句又得重新写上一个方法,非常的麻烦;
我们心里的第一想法就是对这个方法进行优化,我们可以利用一些设计模式来对其进行优化;
public interface MyPredicate<T> {
public boolean test(T t);
}
我们写上一个类来实现这个接口,如果员工的年龄大于35的话,我们就返回true:
public class FilterEmployeeByAge implements MyPredicate<Employee> {
@Override
public boolean test(Employee emp) {
return emp.getAge()>=35;
}
}
我们就可以这样来用了:
public List<Employee> filterEmployees(List<Employee> list,MyPredicate<Employee> mp) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (mp.test(emp)) {
emps.add(emp);
}
}
return emps;
}
然后,我们就可以对其进行测试了:
这个时候,我们对接口的实现类进行扩展就可以了,给它什么策略进行过滤,就可以按照什么方式来进行过滤;但是这种方式不好的地方就是:每次实现一个策略的时候,还要单独的写上一个类;
List<Employee> list = filterEmployees(this.employees, (e) -> e.getSalary() <= 5000)
list.forEach(System.out::println);
/** 仅仅就是对上面数据进行过滤,其他的什么之前的接口都没有 */
@Test
public void test7() {
employees.stream()
.filter((e) -> e.getSalary()>=5000)
.forEach(System.out::println);
}
测试结果如下:
如果我们只想取这四条数据的前面两条:我们还可以这样来写:
我们还可以举一个常见的操作的栗子:把员工信息里面的所有的员工的名字给提取出了,我们就可以这样来写:
/** 把员工信息里面的所有的名字给提取出来 */
@Test
public void test8() {
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
一、Lambda表达式的基本语法:
Java8中引入了一个新的操作符"->"该操作符也称为箭头操作符或Lambda操作符;箭头操作符将Lambda表达式拆分成两部分;
() -> System.out.println("Hello World!");
举例如下:这是两种不同的实现方式:
@Test
public void test1() {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!");
}
};
runnable.run();
Runnable runnable1 = () -> System.out.println("Hello World!");
runnable1.run();
}
有一个小的注意事项:在局部内部类中,引用了一个同级别的局部变量时,在Jdk1.7的时候是会报错的,但在Jdk1.8是可以的,实际上它是省略了final关键字,默认给我们加上了:
(x) -> System.out.println(x);
举例,代码如下:
@Test
public void test2() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("我爱Java");
}
分析如下:对接口中抽象方法的实现
3. 语法格式三:若只有一个参数的话,小括号可以省略不写,但是一般我们通常都给它写上。
x -> System.out.println(x);
举例代码如下:
@Test
public void test3() {
Consumer<String> con = x -> System.out.println(x);
con.accept("我爱Java");
}
@Test
public void test4() {
Comparator<Integer> com = (x,y)->{
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
@Test
public void test5() {
Comparator<Integer> com = (x,y)->Integer.compare(x, y);
}
@Test
public void test6() {
Comparator<Integer> com = (Integer x,Integer y)->Integer.compare(x, y);
}
总结:
(1)左右遇一括号省:"->“左边只有一个参数时,括号可以省;”->"右边只有一条语句时,大括号可以省;
(2)左侧推断类型省:左侧的参数列表里面的参数可以根据上下文进行类型的推断,可以省略数据类型不写;
二、Lambda表达式需要函数式接口的支持:
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用一个注解:@FunctionalInterface来进行修饰一下,可以检查当前的接口是否为函数式接口;
简单使用一下:
需求:对一个数进行运算
1)定义一个接口:
@FunctionalInterface
public interface MyFunction {
public Integer getValue(Integer num);
}
2)定义一个方法:传入一个数和一个接口,接口在调用的时候利用Lambda进行实现:
public Integer operation(Integer num, MyFunction myFun) {
return myFun.getValue(num);
}
3)利用Lambda表达式对接口进行实现,并且重写里面的方法:
@Test
public void test(){
Integer num = operation(100, x -> x * x);
System.out.println(num);
}
如果我们想要进行加法的运算,我们就可以这样来写:
@Test
public void test9(){
System.out.println(operation(200, (y)->y+200));
}