声明:本文为个人学习心得,不代表实际情况,有错误请指出
注意!java1.8的特性中以函数式接口和Lambda 表达式为主的方法引用、Stream API、Optional 类是同一种风格的编程方式,这几种配套使用才能发挥出它们的最大优势。本人观点是能不使用就不使用,只有在必须需要它来优化代码和逻辑时再使用。切莫为了装* 而装*.
这几种特性写出来的代码对于不了解它的码农来说就是噩梦,难以理解,可读性极差。并且学习之路也陡峭,没有一个月的业余学习时间是根本无法正常使用的。但是对于熟悉这种编程方式的人来说就是如鱼得水,编程效率和代码可读性可以得到很大的提升,少写许多冗余的代码
函数式接口主要包括以下几个接口和衍生出来的其他接口:
1.Consumer<T> 代表了接受一个输入参数T并且无返回的操作
2.Function<T,R>接收一个参数T,返回R
3.Predicate<T>接收一个参数T返回一个boolean类型的值
本文主要讲解前三种
学习函数式最好掌握以下知识点,不会也没关系,只是学习比较吃力:
1.java1.8中 default 修饰的默认方法
2.java1.8中 lambda表达式
3.java1.8中 方法引用
1.Consumer< T>
java源码:Iterable接口中的默认方法foreach参数就是Consumer类型
代码001
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
调用方式如下几种方式:
代码002
List<User> userList=new ArrayList<>();//数据省略不写
//1.普通for循环
for(int i=0;i<userList.size();i++){
System.out.println(userList.get(i).getName());
}
//2.foreach
for(User user:userList){
System.out.println(userList.get(i).getName());
}
//3.重点:最复杂,新手最易懂的方式
userList.forEach(user->{
System.out.println(user.getName());
});
//4.函数式参数只有一句代码时可以简化去掉大括号,去掉分号
userList.forEach(user -> System.out.println(user.getName()));
以上所有方式的代码打印结果一致
根据代码上边001的源码分析可知for循环中action.accept(t); 的参数就是代码002中的user ,
user的名字随便起,相当于002代码里函数式代码的引用,System.out.println(user.getName()) 就是函数式的参数,在函数式参数的代码块中可以引用其他地方的变量,(注意!引用时,在代码块外所有变量相当于被final修饰),如下:
直接赋值会编译报错!
测试使用代码如下:
public static void main(String[] args) {
User user=new User(1,"Jack");
test1(user,u->{
System.out.println("我的朋友是:"+u.getName());
});
test1(user,u->{
System.out.println("我的哥哥是:"+u.getName());
});
}
public static void test1(User user,Consumer<? super User> consumer){
System.out.println("----这里是大量逻辑代码1");
consumer.accept(user);
System.out.println("----这里是大量逻辑代码2");
}
运行结果:
2.Function<T,R>
Function相较于Consumer多了个返回值
测试代码如下:
public static void main(String[] args) {
callTest2();
}
public static void callTest2(){
List<User> userList=new ArrayList(){{
add(new User(11,"Jack"));
add(new User(12,"zhangsan"));
add(new User(23,"lisi"));
add(new User(34,"wangwu"));
}};
test2(userList,user -> {
if(user.getAge()<18){
return "未成年";
}
return "已经成年";
});
}
public static void test2(List<User> list, Function<? super User,? extends String> function){
System.out.println("----这里是大量逻辑代码1");
list.forEach(user->{
System.out.println(user.getName()+":"+function.apply(user));
});
System.out.println("----这里是大量逻辑代码2");
}
运行结果:
3.Predicate< T>
Predicate为参数时,代码块内要返回一个boolean值
我参考list.stream().filter()写出如下测试代码
public static void callTest3(){
List<User> userList=new ArrayList(){{
add(new User(11,"Jack"));
add(new User(12,"zhangsan"));
add(new User(23,"lisi"));
add(new User(34,"wangwu"));
}};
//得到年龄大于18岁的人
List<User> =test3(userList,user -> {
return user.getAge()>18
});
//上边的代码可以这样简化
System.out.println("大于18岁的");
List<User> list3=test3(userList,user ->user.getAge()>18);
list3.forEach(user -> System.out.println(user.getAge()));
System.out.println("名字中含有'z'的");
List<User> list4=test3(userList,user ->user.getName().contains("z"));
list4.forEach(user -> System.out.println(user.getName()));
list3.stream().filter()
}
public static List<User> test3(List<User> list, Predicate<? super User> predicate){
Objects.requireNonNull(list);//提前判空
List<User> userList=new ArrayList<>();
list.forEach(user->{
if(predicate.test(user)){
userList.add(user);
}
});
return userList;
}
运行结果:
版权声明:本文为博主原创文章,未经博主允许不得转载。