Lambda表达式
在开始java8新特性前,回顾一下上周学过的lambda表达式。
多线程那块也比较薄弱;
格式
-> lambda操作符
左边:形参列表
右边:lambda体,(重写的抽象方法的方法体)
总结:左边,如果lambda形参列表只有一个参数,()可以省略。
右边,如果只有一条执行语句,省略这对{}和return关键字。
因为感觉理解深度不够,去看了原视频
下面这个例子,com2用了常规的lambda,com3使用了方法引用对2的结果进行进一步的优化。
@Test
public void test2(){
Comparator<Integer> com1=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare1 = com1.compare(12, 21);
System.out.println(compare1);
System.out.println("***********");
Comparator<Integer> com2=(o1,o2)->Integer.compare(01,02);
int compare2=com2.compare(32,12);
System.out.println(compare2);
System.out.println("******");
Comparator<Integer> com3=Integer:: compare;
int compare3=com3.compare(32,12);
System.out.println(compare3);
};
函数式接口
接口中之声明了一个抽象方法,称为函数式接口。
@FunctiionalInterface注解
lambda表达式本质:作为函数式接口的实例。
当需要对一个函数式接口实例化时,可以使用lambda表达式。
java内置四大核心函数式接口
Consumer 消费型接口 void accept(T t){}
Supplier 供给型接口 T get()
Function<T,R> R apply(T t)
Predicate 断定型接口 boolean test(T t) 用来确定类型为T的对象是否满足某约束,返回boolean值
举例:要有抽象的能力
public class LambdaTest2 {
@Test
public void test1(){
List<String> list= Arrays.asList("北京","dongjing","xijing","wangjing");
List<String> filterStrs = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("jing");
}
});
System.out.println(filterStrs);
System.out.println("***********");
List<String> filterStrs1 = filterString(list,s->s.contains("jing"));
System.out.println(filterStrs1);
}
//根据给定的规则,过滤集合中的字符串。此规则有predicate的方法决定
public List<String> filterString(List<String> list, Predicate<String> pre){
ArrayList<String> filterList = new ArrayList<>();
for(String s:list){
if(pre.test(s)){
filterList.add(s);
}
}
return filterList;
}
}
Stream API
对数据的运算 与cpu打交道
集合关注数据存储
类似于数据库中对表的操作
jdbc底层原理:一套有接口的api 可以操作数据库
-
注意点:
1、Stream自己不会存储对象
2、不会改变源对象
3、操作时延迟执行 -
使用流程
实例化
中间操作
终止操作 -
注意点
一个中间操作连,对数据源数据进行处理
一旦执行终止操作,执行中间操作链,并产生结果,之后,不再被使用。 -
步骤1、Stream实例化
public class StreamAPITest {
@Test
public void test1(){
//创建Stream方式一:通过集合获取
List<Employee> employees = EmployeeData.getEmployees();
//返回一个顺序流
Stream<Employee> stream = employees.stream();
//并行流
Stream<Employee> parallelStream = employees.parallelStream();
}
//创建Stream方式二:通过数组
@Test
public void test2(){
int[] arr=new int[]{1,2,3,4,5,6};
//arrays类中静态方法
IntStream stream = Arrays.stream(arr);
Employee e1=new Employee(1001,123);
Employee e2=new Employee(1002,123);
Employee[] arr1=new Employee[]{e1,e2};
Stream<Employee> stream1 = Arrays.stream(arr1);
}
//方式三:通过stream的of方法
@Test
public void test3(){
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
}
}
-中间操作
筛选与切片
public class StreamAPITest1 {
@Test
public void test1(){
List<Employee> list = EmployeeData.getEmployees();
Stream<Employee> stream = list.stream();
//查询员工表中薪资大于7000员工信息
stream.filter(e->e.getAge()>10).forEach(System.out::println);
System.out.println();
//limit(n)-截断流 重新生成stream
list.stream().limit(3).forEach(System.out::println);
System.out.println();
//skip 跳过元素
list.stream().skip(3).forEach(System.out::println);
}
}
映射
map(Function f):接收一个函数作为参数,将元素转为其他形式或提取信息
@Test
public void test2(){
List<String> list = Arrays.asList("aa", "dd", "cc");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
}
映射后面有个flatmap 跳过了
排序
@Test
public void test3(){
List<Integer> list = Arrays.asList(1, 3, 2, 4, 2, 5, 2);
list.stream().sorted().forEach(System.out::println);
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2)->{
return Integer.compare(e1.getAge(),e2.getAge());
}).forEach(System.out::println);
}
-终止操作
- 匹配与查找
@Test
public void test1(){
List<Employee> employees = EmployeeData.getEmployees();
boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
}
规约
reduce(T identity,BinaryOperator):可以将流中元素反复结合,得到一个值。
收集 将流转为其他形式
Option类的使用
容器 可以保存类型T的值,代表值存在。
避免空指针异常
Optional类
为了解决java中空指针问题
go语言 java的运行效率
scalar
python写的快 不用关注运行效率
- 常用方法
public class OptionalTest {
@Test
public void test1(){
Optional<Object> op1=Optional.empty();
if(op1.isPresent()){
System.out.println("数据为空");
}
//System.out.println(op1.get());
System.out.println(op1);
System.out.println(op1.isPresent());
}
@Test
public void test2(){
String str2="hello";
//封装数据,要求对象不能为空
Optional<String> op1 = Optional.of(str2);
//get方法通常和of方法搭配使用,用于获取内部封装数据。
String s = op1.get();
System.out.println(s);
}
@Test
public void test3(){
//String str="jei";
String str=null;
//封装数据t赋值给optional内部value
Optional<String> op1 = Optional.ofNullable(str);
//orElse(T t1):如果内部value非空,返回此value值
String str2 = op1.orElse("shangha");
System.out.println(str2);
}
}
lambda表达式是一个函数式接口实例。
lambda表达式是一个函数式接口实例
lambda表达式是一个函数式接口实例。
方法引用
使用情景:当要传递给lambda体的操作,已经有实现的方法,可以使用方法引用。
它也是lambda表达式,可以看成是语法糖
你看一下,Consumer中的void accept(T t)
和 PrintStream中的void println(T t) 结构一致,所以下面的东西可以做如此修改
- 情况一:
Consumer<String> con1=str->System.out.println(str);
等价于
PrintStream ps=System.out;
Consumer<String> con2=ps::println;
需要判断使用类或者对象,方法是不是静态的。
例子2、
Employee emp=new Employee(id:1001,name:"Tom");
Supplies<String> sup1=()->emp.getName();
等价于
Supplies<String> sup2=emp::getName;
- 情况二
类::静态变量
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
eg1:
Comparator<Integer> com1=(t1,t2)->Integer.compare(t1,t2);
等价于
Comparator<Integer> com2=Integer::compare;
//这个也简单好理解
eg2
Function<Double,Long> func1=d->Math.round(d);
//等价于
Function<Double,Long> func2=Math::round;
- 情况三 类::实例方法
//Comparator中的int compare(T t1,T t2)
//String中的int t1.compareTo(t2)
eg1:
Comparator<String> com1=(s1,s2)->compareTo(s2);
等价与
Comparator<String> com1=String::compareTo;
//两个参数时,如果第一个方法作为调用者出现,也存在引用,但是是用类
eg2
BiPredicate<String,String> pre1=(s1,s2)->s1.equals(s2);
//等价于
BiPredicate<String,String> pre2=**String**::equals;
eg3:
Function<Employee,String> func1=e->e.getName();
//等价于
Function<Employee,String> func2=Employee::getName;
//就上面三种,重要的就是判断条件,做出选择
构造器引用
//Supplier中的T get()
//Employee的空参构造器:Employee()
原始构造器写法
eg1:
Supplier<Employee> sup=new Supplier<Employee>(){
public Employee get(){
return new Employee();
}
}
Supplier<Employee> sup1=()->new Employee();
//等价于
Supplier<Employee> sup2=Employee::new;
eg2:
Function<Integer,Employee> func1=new Employee(id);
//等价于
Function<Integer,Employee> func2=Employee::new;
总结:构造器引用和方法引用类似
数组引用
把数组看成类类型。
数组类型[] ::new
Function<Integer,Integer[]> fun=(n)->new Integer[n];
等同于
Function<Integer,Integer[]> fun=Integer[]::new;
e2:
Function<Integer,String[]> func1=length->new String[length];
//等同于
Function<Integer,String[]> func2=String[]::new;
java8新特性(csdn文章)
循环遍历
前:
for(User user :users){
sout(user.toString());
}
现在:
users.foreaach(o->sout(o.toString()));
2、函数式编程:匿名内部类
before:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
}).start();
after:
new Thread(() -> System.out.println("hello world")).start();
3、排序(升序)
before:
Collections.sort(userList,new Comparator<User>()){
@Override
public int compare(User o1,User o2){
return o1.getAge()-o2.getAge();
}
}
注意一下,数值比较可以直接相减排序;如果是非数值比较,应当使用compareTo()方法
return o1.getName().compareTo(o2.getName());
after1:
Colletions.sort(userList,(01,02)->o1.getAge()-o2.getAge());
after2:
在这里插入代码片
5、过滤