在开始java8新特性前,回顾一下上周学过的lambda表达式。
多线程那块也比较薄弱;
格式
-> lambda操作符
左边:形参列表
右边:lambda体,(重写的抽象方法的方法体)
总结:左边,如果lambda形参列表只有一个参数,()可以省略。
右边,如果只有一条执行语句,省略这对{}和return关键字。
因为感觉理解深度不够,去看了原视频
下面这个例子,com2用了常规的lambda,com3使用了方法引用对2的结果进行进一步的优化。
@Test
public void test2(){
Comparator com1=new Comparator() {
@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 com2=(o1,o2)->Integer.compare(01,02);
int compare2=com2.compare(32,12);
System.out.println(compare2);
System.out.println("******");
Comparator 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
Predicate 断定型接口 boolean test(T t) 用来确定类型为T的对象是否满足某约束,返回boolean值
举例:要有抽象的能力
public class LambdaTest2 {
@Test
public void test1(){
List list= Arrays.asList("北京","dongjing","xijing","wangjing");
List filterStrs = filterString(list, new Predicate() {
@Override
public boolean test(String s) {
return s.contains("jing");
}
});
System.out.println(filterStrs);
System.out.println("***********");
List filterStrs1 = filterString(list,s->s.contains("jing"));
System.out.println(filterStrs1);
}
//根据给定的规则,过滤集合中的字符串。此规则有predicate的方法决定
public List filterString(List list, Predicate pre){
ArrayList 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 employees = EmployeeData.getEmployees();
//返回一个顺序流
Stream stream = employees.stream();
//并行流
Stream 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 stream1 = Arrays.stream(arr1);
}
//方式三:通过stream的of方法
@Test
public void test3(){
Stream stream = Stream.of(1, 2, 3, 4, 5);
}
}
-中间操作
筛选与切片
public class StreamAPITest1 {
@Test
public void test1(){
List list = EmployeeData.getEmployees();
Stream 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 list = Arrays.asList("aa", "dd", "cc");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
}
映射后面有个flatmap 跳过了
排序
@Test
public void test3(){
List list = Arrays.asList(1, 3, 2, 4, 2, 5, 2);
list.stream().sorted().forEach(System.out::println);
List employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2)->{
return Integer.compare(e1.getAge(),e2.getAge());
}).forEach(System.out::println);
}
-终止操作
- 匹配与查找
@Test
public void test1(){
List 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
lambda表达式是一个函数式接口实例。
lambda表达式是一个函数式接口实例
lambda表达式是一个函数式接口实例。
使用情景:当要传递给lambda体的操作,已经有实现的方法,可以使用方法引用。
它也是lambda表达式,可以看成是语法糖
你看一下,Consumer中的void accept(T t)
和 PrintStream中的void println(T t) 结构一致,所以下面的东西可以做如此修改
- 情况一:
Consumercon1=str->System.out.println(str);
等价于
PrintStream ps=System.out; Consumercon2=ps::println;
需要判断使用类或者对象,方法是不是静态的。
例子2、
Employee emp=new Employee(id:1001,name:"Tom"); Suppliessup1=()->emp.getName();
等价于
Suppliessup2=emp::getName;
- 情况二
类::静态变量
//Comparator中的int compare(T t1,T t2)
//Integer中的int compare(T t1,T t2)
eg1:
Comparatorcom1=(t1,t2)->Integer.compare(t1,t2);
等价于
Comparatorcom2=Integer::compare;
//这个也简单好理解
eg2
Functionfunc1=d->Math.round(d); //等价于 Function func2=Math::round;
- 情况三 类::实例方法
//Comparator中的int compare(T t1,T t2)
//String中的int t1.compareTo(t2)
eg1:
Comparatorcom1=(s1,s2)->compareTo(s2); 等价与 Comparator com1=String::compareTo; //两个参数时,如果第一个方法作为调用者出现,也存在引用,但是是用类
eg2
BiPredicatepre1=(s1,s2)->s1.equals(s2); //等价于 BiPredicate pre2=**String**::equals;
eg3:
Functionfunc1=e->e.getName(); //等价于 Function func2=Employee::getName;
//就上面三种,重要的就是判断条件,做出选择
构造器引用//Supplier中的T get()
//Employee的空参构造器:Employee()
原始构造器写法
eg1:
Suppliersup=new Supplier (){ public Employee get(){ return new Employee(); } }
Suppliersup1=()->new Employee(); //等价于 Supplier sup2=Employee::new;
eg2:
Functionfunc1=new Employee(id); //等价于 Function func2=Employee::new;
总结:构造器引用和方法引用类似
数组引用把数组看成类类型。
数组类型[] ::new
Functionfun=(n)->new Integer[n];
等同于
Functionfun=Integer[]::new;
e2:
Functionjava8新特性(csdn文章)func1=length->new String[length]; //等同于 Function func2=String[]::new;
循环遍历
前:
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()){ @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、过滤
文件流操作(复习)


