JAVA8 Lambda表达式到底优不优雅?
今天看到一个关注很久的公众号,作者是一个10年+的程序员,现在自主创业,他原文中是这么说的:多去看看外面的世界,不要把自己封闭在技术的圈子内,这对自己不管是创业还是挣钱,都有莫大的帮助;
个人虽然很同意他的说法,但是带来的问题就是你如何跻身于高端的,创业大佬的,技术大牛的圈子,人家张嘴就是技术潮流,闭嘴就是互联网一线信息,个人还是觉得踏实提升自己,对于投资自己的脑袋这件事深表认同。
目前JAVA版本每半年更新已到JAVA12了,虽然工作中用的是JDK1.8,但不用他的特性是不是有点浪费?针对各个版本的新特性,应该1.8是相当稳定,适用性最多,使用率最高的版本,毕竟新版本还有待市场考察。
那么JAVA8到底有多优雅呢?首先看下都有神马新特性
我们从代码角度体会下JAVA8的好处;
需求:设计接口实现对对象属性的过滤。
方案:除去SQL编写方式外,一般我们都会针对接口编程
公共属性:Employee
public class Employee {
private Integer id;
private Integer age;
private Integer salary;
private String name;
public Employee(Integer id, Integer age, Integer salary, String name) {
this.id = id;
this.age = age;
this.salary = salary;
this.name = name;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", age=" + age +
", salary=" + salary +
", name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Employee() {
}
public Employee(Integer id, Integer age, Integer salary) {
this.id = id;
this.age = age;
this.salary = salary;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
}
方案一:针对接口编程,定义接口,逻辑放在实现类
public interface MyProduce<T> {
boolean bySalary(Employee employee);
}
public class MyProduceImpl implements MyProduce<Employee> {
@Override
public boolean bySalary(Employee employee) {
return employee.getSalary()>5000;
}
}
public class TestJava8 {
List<Employee> employees= Arrays.asList(
new Employee(1,20,2000,"张三"),
new Employee(2,30,28000,"李四"),
new Employee(3,40,1000,"王五"),
new Employee(4,50,5000,"赵六")
);
}
实现过滤工资小于5000的员工
public List<Employee> filterEmployee(List<Employee> list,MyProduce<Employee> mp) {
List<Employee> emps = new ArrayList<>();
for (Employee employee : list) {
if (employee.getSalary() < 5000) {
emps.add(employee);
}
}
return emps;
}
@Test
public void test1(){
List<Employee> employees = filterEmployee(this.employees, new MyProduce<Employee>() {
@Override
public boolean bySalary(Employee employee) {
return employee.getSalary() <5000;
}
});
for (Employee employee : employees) {
System.out.println(employee);
}
}
方案二:匿名内部类
@Test
public void test2(){
List<Employee> employee = filterEmployee(employees, new MyProduce<Employee>() {
@Override
public boolean bySalary(Employee employee) {
return employee.getSalary() < 5000;
}
});
for (Employee emp : employee) {
System.out.println(emp);
}
}
方案三:Lambda表达式
@Test
public void test3(){
List<Employee> employees = filterEmployee(this.employees,(e)->e.getSalary()>5000);
employees.forEach(System.out::println);
}
方案四:Stream流,工资大于5000的前2位员工,打印出员工的名称,不需要任何接口
@Test
public void test4(){
employees.stream()
.filter((e)->e.getSalary()>=5000)
.limit(2)
.forEach(System.out::println);
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
省掉了各种过滤的接口,各种实现方法的调用,且流式调用,要多方便有多方便,要多简洁有多简洁。代码量更少,功能更强大
Lambda表达式
为什么使用 Lambda 表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda表达式的语法
Lambda 表达式在Java 8 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的参数列表
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
函数式接口:接口中只有一个抽象方法的接口,SAM类型的接口(Single Abstract Method)。定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个lambda表达式作为参数
语法格式:
1.0:无参数无返回值
() ->System.out.println(“Hello”);
2.0:有一个参数无返回值
Consumer<String> con=(x)->System.out.println(“x”);
3.0: 只一个参数无返回值,小括号可以省略不写
习惯上写小括号
4.0:多个参数,有返回值,Lambda体中有多条语句
Comparator<Integer> com=(x,y)->{
System.out.println(“多条语句”);
return Integer.compare(1,2);
};
5.0:多个参数,有返回值,Lambda体中有一条语句,return 和大括号都可以不写
6.0:Lambda参数列表的类型可以省略不写,JVM可通过向上下文推断数据类型
总结:左右遇一括号省,
左侧推断类型省,
@FunctionalInterface检查是否是函数式接口
默认方法与静态方法并不影响函数式接口的契约,可以任意使用
可以有 Object 中覆盖的方法,也就是 equals,toString,hashcode等方法。
JDK 8之前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.util.Comparator
java.io.FileFilter
java.lang.reflect.InvocationHandler
import java.util.Objects;
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/*表示接受单个输入参数,并返回无返回值。与大多数其他功能接口不同,需要@code consumer*通过副作用操作@FunctionalInterface
public interface Consumer<T> {}
注意事项:
@Test
public void test5(){
int num=8;//????
Runnable r=new Runnable(){
@Override
public void run() {
System.out.println("Hello:"+"\t"+num);
}
};
r.run();
Runnable r1= ()-> System.out.println("HELLO:"+"\t"+num);
r1.run();
}
在1.8以前局部内部类中应用了一个同级别的局部变量,他应该是final的
但是为什么java8不需要也能编译通过呢?其实底层他还是final的,我们验证一下
变量num是来自内部类,需要final或者实际上是final的,说明1.8进行了底层加final;
然后说下网上的关于java8 Lambda表达式的性能问题。搜索结果验证说用了Lambda反而性能下降了,执行foreach时间长了,特别是大数据遍历。还拿了并行代码对比,我觉得要看实际的用途,看看Lambda解决问题的侧重点,lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名类。
本身就是侧重于减少代码冗余的,你非得谈性能?
6月最后一天啊,针对于年初计划,执行情况做一下小总结,年初定了年度计划目标,年中,年末做一个检查,5年后回味自己的今天,希望有质的提升
2019年6月30日:
1.今天是听得到APP历史记录1242条的一天。
2.今天是百词斩APP背单词累计的第394天,背单词数4866个
3.今天是一年写40篇文章计划的第26篇
好的今天记录就到这里。
- 点赞
- 收藏
- 关注作者
评论(0)