1. Lambda 表达式
在JDK8之前,Java是不支持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为一个参数进行传递。通常我们提及得更多的是面向对象编程,面向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。在JavaScript中这是很常见的一个语法特性,但在Java中将一个函数作为参数传递这却行不通,好在JDK8的出现打破了Java的这一限制。
Lambda表达式一共有三部分组成:
-
左侧是一个小括号,里面是要实现的抽象方法的参数,有几个参数就写几个参数名,无参可写空括号,无需声明参数类型;
-
中间是一个jdk8新定义的箭头符号;
-
右侧是一个大括号,在括号内编写抽象方法的实现内容,有参时,可直接使用左侧括号中的对应参数,与正常方法的方法体相同;
-
使用方式:实现只有一个抽象方法的接口时会自行匹配到该方法,在箭头左侧编写对应参数个数的参数名,箭头右侧编写方法的实现代码(代码实现为单行时可去掉大括号{})
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello java8");
}
}).start();
new Thread(()-> System.out.println("hello java8.0")).start();
}
hello java8
hello java8.0
将代码逻辑当做参数传递给方法
public static Integer getAge(Function<String, Integer> function, String args) {
return function.apply(args);
}
public static void main(String[] args) {
System.out.println(getAge(a->Integer.parseInt(a),"112"));
}
//112
复杂的需求根据不同颜色和重量获取数据
@Data
public class Apple {
private Integer id;
private String color;
private Integer weight;
private String origin;
public Apple(Integer id, String color, Integer weight, String origin) {
this.id = id;
this.color = color;
this.weight = weight;
this.origin = origin;
}
}
main
public List<Apple> getApplesByPredicates(Predicate<Apple> predicate) {
ArrayList list = new ArrayList();
for (Apple apple : apples) {
if(predicate.test(apple)){
list.add(apple);
}
}
//简单的stream表达式
//return apples.stream().filter(predicate).collect(Collectors.toList());
return list;
}
public static void main(String[] args) {
AppServer appServer = new AppServer();
appServer.apples.add(new Apple(10,"red",200,"gz"));
appServer.apples.add(new Apple(11,"green",201,"gzs"));
appServer.apples.add(new Apple(13,"red",201,"gzd"));
List<Apple> red = appServer.getApplesByPredicates(apple -> apple.getColor().equals("red")&&apple.getId()>10);
for (Apple apple : red) {
System.out.println("id:"+apple.getId());
System.out.println("color:"+apple.getColor());
}
}
id:13
color:red
自定义函数式接口
@FunctionalInterface
public interface MyFunction {
//加了@FunctionalInterface注解
//接口中只有唯一的抽象方法,自动推导成函数式接口
//如果多余的抽象方法是Object的方法,不印象第一条
void sayHello();
@Override
String toString();
default void sayHello2(){};
}
1.1 三种编写方式
- expression 单条语句表达式
- statement 语句块
- refrence 方法引用
1.2 expression 只能是一个语句
两个参数
@FunctionalInterface
public interface MyFunction {
//加了@FunctionalInterface注解
//接口中只有唯一的抽象方法,自动推导成函数式接口
//如果多余的抽象方法是Object的方法,不印象第一条
void sayHello(String name,String content);
@Override
String toString();
default void sayHello2(){};
}
main方法
MyFunction myFunction = ((name, content) -> System.out.println(name + content));
myFunction.sayHello("张三,", "你好 java!");
//结果: 张三,你好 java!
1.3 statement 语句块,执行多个代码段
@FunctionalInterface
public interface MyFunction2 {
//加了@FunctionalInterface注解
//接口中只有唯一的抽象方法,自动推导成函数式接口
//如果多余的抽象方法是Object的方法,不印象第一条
String sayHello(String name,String content);
@Override
String toString();
default void sayHello2(){};
}
main方法
public static void main(String[] args) {
MyFunction2 myFunction = ((name, content) -> {
System.out.println(name);
System.out.println(content);
return name+content;
});
System.out.println(myFunction.sayHello("张三,", "你好 java!"));
}
结果
张三,
你好 java!
张三,你好 java!
1.4 refrence 引用
实例方法引用
public class RefrenceTest {
public String sayHello(String name) {
System.out.println(name);
return name + "say hi";
}
static void test1() {
RefrenceTest test = new RefrenceTest();
Function<String, String> f = test::sayHello;
System.out.println(f.apply("李四"));
}
public static void main(String[] args) {
test1();
}
}
李四
李四say hi
1.5 老版本的Java中排列字符串
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
1.6 Java 8提供了更简洁的语法,lambda表达式:
public class Lambda {
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
public void test(){
Collections.sort(names,(String a, String b)->{
return b.compareTo(a);
});
}
}
2. Stream流
@Data
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
数据
static List<User> list = Arrays.asList(
// name,age
new User("张三", 11),
new User("王五", 20),
new User("王五", 91),
new User("张三", 8),
new User("李四", 44),
new User("李四", 44),
new User("李四", 44)
);
2.1 stream lambda
// java 8 stream lambda
list.stream().forEach(user -> System.out.println(user));
User(name=张三, age=11)
User(name=王五, age=20)
User(name=王五, age=91)
User(name=张三, age=8)
User(name=李四, age=44)
User(name=李四, age=44)
User(name=李四, age=44)
2.2 sort
list.stream().sorted(Comparator.comparing(User::getAge)).forEach(System.out::println);
User(name=张三, age=8)
User(name=张三, age=11)
User(name=王五, age=20)
User(name=李四, age=44)
User(name=李四, age=44)
User(name=李四, age=44)
User(name=王五, age=91)
2.3 filter 输出年龄大于50的人
list.stream().filter(user -> user.getAge()>50).forEach(System.out::println);
User(name=王五, age=91)
2.4 limit():使用该方法截断
list.stream().limit(3).forEach(System.out::println);
User(name=张三, age=11)
User(name=王五, age=20)
User(name=王五, age=91)
2.5 skip():与limit互斥,使用该方法跳过元素
list.stream().skip(3).forEach(System.out::println);
User(name=张三, age=8)
User(name=李四, age=44)
User(name=李四, age=44)
User(name=李四, age=44)
2.6 distinct():使用该方法去重,注意:必须重写对应泛型的hashCode()和equals()方法
list.stream().distinct().forEach(System.out::println);
User(name=张三, age=11)
User(name=王五, age=20)
User(name=王五, age=91)
User(name=张三, age=8)
User(name=李四, age=44)
2.7 max,min,sum,avg,count
IntSummaryStatistics num = list.stream().mapToInt(value -> value.getAge()).summaryStatistics();
System.out.println("总共人数:" + num.getCount());
System.out.println("平均年龄:" + num.getAverage());
System.out.println("最大年龄:" + num.getMax());
System.out.println("最小年龄:" + num.getMin());
System.out.println("年龄之和:" + num.getSum());
总共人数:7
平均年龄:37.42857142857143
最大年龄:91
最小年龄:8
年龄之和:262
2.8 map():接收一个方法作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
List<String> words = Arrays.asList("aaa", "vvvv", "cccc");
words.stream().map(s -> s.toUpperCase()).collect(Collectors.toList()).forEach(System.out::println);
AAA
VVVV
CCCC
2.9 reduce
//reduce 操作可以实现从一组元素中生成一个值
//sum()、max()、min()、count()等都是reduce操作,将他们单独设为函数只是因为常用
//例如:找到年龄最大的
Optional<User> reduce1 = list.stream().reduce((user, user2) -> user.getAge() > user2.getAge() ? user : user2);
System.out.println(reduce1.get());
User(name=王五, age=91)