引入lambda
第一次使用
在test01 我们写了一个内部类 比较大小 实际有用的话就这一句 很麻烦
在test02 用lambda表达式优化
package com.lijiawei;
import org.junit.Test;
import java.net.Inet4Address;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeSet;
public class Testlambda {
@Test
public void test01(){
//原来使用treeset排序得写一个匿名内部类
Comparator<Integer> com = new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2) {
return Integer.compare(o1,o2);//实际就这一句话有用
}
};
TreeSet<Integer> ts = new TreeSet<Integer>(com);
ts.add(2);
ts.add(1);
System.out.println(ts);
}
@Test
public void test02(){
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> ts = new TreeSet<Integer>(com);
ts.add(2);
ts.add(1);
System.out.println(ts);
}
@Test
public void test03(){
}
}
一个需求
查询所有年纪大于20的人
List<Employee> list = Arrays.asList(
new Employee("张三",28,5000),
new Employee("李四",8,10000),
new Employee("王五",38,2000),
new Employee("赵六",48,4500)
);
@Test
public void test03(){
List<Employee> a = filterAge(list);
System.out.println(a);
}
//查出年龄大于10岁的
public List<Employee> filterAge(List<Employee> list){
List<Employee> employees = new ArrayList<>();
for (Employee e :list){
if(e.getAge()>10){
employees.add(e);
}
}
return employees;
}
//查出工资大于5000的
public List<Employee> filterAge2(List<Employee> list){
List<Employee> employees = new ArrayList<>();
for (Employee e :list){
if(e.getSalary()>5000){ //和上面的方法就变了这一句话
employees.add(e);
}
}
return employees;
}
如果我又加一个需求 要求出工资大于5000并且年龄大于20的人 那是不是又得写一个方法 需求一变 就要改变原来的代码 这样不好
策略模式优化
定义一个接口
package com.Inter;
public interface Myfilter<T> {
public boolean test(T t);
}
定义实现类
package com.Inter;
import com.pojo.Employee;
public class ImplMyfilter implements Myfilter<Employee>{
@Override
public boolean test(Employee employee) {
return employee.getAge()>35;
}
}
测试类
public List<Employee> show(List<Employee> list , Myfilter<Employee> im ){
List<Employee> employees =new ArrayList<>();
for (Employee employee:list){
if(im.test(employee)){
employees.add(employee);
}
}
return employees;
}
@Test
public void test04(){
List<Employee> show = show(list, new ImplMyfilter());//如果需求变了 我把这个实例换一下就行
System.out.println(show);
}
如果需求在变 我们只需要增加一个实现类 在调用的时候 new 这个新写的实现类即可 使用场景:商场打折
我们发现策略模式有个缺点 : 创建新功能就得写一个类 所以在优化
匿名内部类优化
匿名内部类直接实现 就不用写类实现了
public void text(){
List<Employee> l = show(list, new Myfilter<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>5000;
}
});
System.out.println(l);
}
匿名内部类优化可读性差 所以在优化
lambda表达式优化
@Test
public void text(){
List<Employee> l = show(list,(e) -> e.getSalary()>5000);
System.out.println(l);
}
还能更简洁 之后使用stream优化 先来学习lambda
lambda语法
注意: j.k1.8以前 匿名内部类引用同级别的变量 那个变量必须显示的写final 8之后默认加了final
-> 操作符分为俩部分 左侧 是抽象类中要重写的方法的参数列表 右侧是要执行的功能
接口中只有一个方法
1无参无返回值
Runnble r = ( ) ->System.Out.Print(“你好”);
2有一个参数无返回值
Consumer c = ( x) ->System.out.Print(“你好”);
只有一个参数 小括号可以不写
3有多个参数有返回值 有多条执行语句
多条语句 使用大括号抱起来
Comparator com= (x,y)->{
System.out.Print(“你好”);
return Integer.compare(x,y);
}
4 如果只有一条语句
return 和大括号可以省略
Comparator com= (x,y) -> Integer.compare(x,y);
5不写数据类型
上面的xy 都没有写数据类型 因为jjvm编译器可以类型推断
比如 String[] str=[“aa”,“bb”,“cc”] 这里的内容就是推断出来的 如果你分开写就报错
String[] str; str=[“aa”,“bb”,“cc”] //报错
再看这个上面写过的 我们e按下点的时候就提示有getSalary方法 他怎么知道我是什么类型的呢?根据目标类型推断出这是什么类型
List l = show(list,(e) -> e.getSalary()>5000);
因为不能写方法名 当接口有多个方法时java不知道重写的是哪个方法 所以借口不能写多个抽象方法
函数式接口
只有一个抽象方法的接口叫函数式接口 在接口上加注解@FunctionInterface 可以帮我们检查这个接口是不是函数式接口
内置函数式接口
每次们用一个功能 都要自己定义一个函数式接口 java想到了这一点 所以有四个内置的接口
Consumer void acept(T t) 消费型接口
public class TestLamda{
@Test
public void test(){
show(100,(a)-> System.out.println("消费了"+a));
}
public void show(Integer number, Consumer<Integer> consumer){
consumer.accept(number);
}
}
Supplier T get(); 供给型接口
package com.lijiawei;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void test(){
List l = show(10,() -> (int)(Math.random()*10));
System.out.println(l);
}
public List<Integer> show(Integer number, Supplier<Integer> supplier){
List<Integer> lists = new ArrayList<>();
for (int i = 0; i <number ; i++) {
lists.add(supplier.get());
}
return lists;
}
}
Function<T,R> R apply(T t) 函数式接口
package com.lijiawei;
import org.junit.Test;
import java.util.function.Function;
public class TestLamda{
@Test
public void test(){
String a = show(" helloworld ",(x) ->x.trim() );
System.out.println(a);
}
public String show(String str, Function<String,String> function){
return function.apply(str);
}
}
predicate boolean test(T t ) 断言型接口
方法引用与构造器引用
若lambda体中的内容已经实现了 我们可以引用
对象::实例方法名
类::静态方法名
类::实例方法名
以下三种写法有个前提 我们写的lambda体的方法的返回值和参数列表要与 函数时接口的抽象方法保持一致
在lambda表达式中 我们写了参数列表 和 方法体并返回了一个东西 这写都是手动写出来的 引用不写但要保持一致
对象::实例方法名
package com.lijiawei;
import org.junit.Test;
import java.util.function.Consumer;
public class TestLamda{
@Test
public void show(){
Consumer<String> consumer1 = System.out::println;
consumer1.accept("zz");
}
}
再看一个例子
无参有返回值 Math::random也必须无参无返回值
package com.lijiawei;
import org.junit.Test;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void show(){
//Supplier<T> T get();
Empoyee emp = new Employee();
Supplier<Double> supplier =emp::getAge;
Double d = supplier.get();
System.out.println(d);
}
}
类::静态方法名
package com.lijiawei;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class TestLamda{
@Test
public void show(){
Comparator<Integer> com = Integer::compare;
int a = com.compare(5,4);
System.out.println(a);
}
}
类::实例方法名
先用lambda表达式 需求 比较俩个字符串是否一样
public void show(){
BiPredicate<String,String> bp = (x,y)->x.equals(y);
boolean b =bp.test("a","a");
System.out.println(b);
}
为什么类名能调用实例方法呢? 当第一个参数是实例方法的调用者 另一个参数是实例方法的参数时 才能这么调
方法引用格式
public void show(){
BiPredicate<String,String> bp = String::equals;
boolean b =bp.test("a","a");
System.out.println(b);
}
构造器引用
如果 方法体是获取对象
Supplier<Employee> s = ()->new Employee();
可以这么写 那用的是有参构造还是无参构造呢 得看函数接口的抽象方法的参数列表有多少个 构造器重载怎么办呢
泛型推断可以该用哪个构造器
Supplier<Employee> s = Employee::new;
StreamAPI
创建流的方式
package com.lijiawei;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestLamda{
@Test
public void show(){
//1获取流第一种方式 集合获取
List a = new ArrayList();
Stream<String> s = a.stream();
Stream<String> s1 =a.parallelStream();
//2数组获取流
String[] str = new String[10];
Stream<String> s3 = Arrays.stream(str);
//3Stream静态方法of
Stream<String> s4 = Stream.of("a","b");
//4无限流 迭代
Stream<Integer> s5= Stream.iterate(0,(x) -> x+2);
s5.forEach(System.out::println);
//4无限流 生成
Stream.generate(()->Math.random())
.limit(10)
.forEach(System.out::println);
}
}
Stream筛选与切片
filter-接收lambda 从流中排除某些元素
limit–截断流 使元素不会超出指定数量
skip(n) --跳过 返回扔掉前n个元素的流 不足n个 则返回空流
distinct --筛选 通过元素生成的hascode和equals 去除重复元素
多个中间操作可以形成流水线 除非触发终止操作 否则中间操作不会做任何处理,在终止操作时全部一次性处理,这叫惰性求值
package com.lijiawei;
import org.junit.Test;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestLamda{
List<Employees> employees = Arrays.asList(
new Employees("张三",18,5000),
new Employees("张三",18,5000),
new Employees("张三",18,5000),
new Employees("李三",20,10000),
new Employees("王三",30,15000)
);
@Test
public void show(){
Stream s = employees.stream()
.filter((e)->e.getAge()>20);
//终止操作
s.forEach(System.out::println);
}
@Test
public void test2(){
employees.stream()
.limit(2)
.forEach(System.out::println);
}
@Test
public void test3(){
employees.stream()
//跳过前俩个
.skip(2)
.forEach(System.out::println);
}
@Test
//筛选
public void test4(){
employees.stream()
.distinct()
.forEach(System.out::println);
}
}
Stream映射
map --接收lambda 将函数 作用到流的每一个元素上
package com.lijiawei;
import org.junit.Test;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestLamda{
List<Employees> employees = Arrays.asList(
new Employees("张三",18,5000),
new Employees("张三",18,5000),
new Employees("张三",18,5000),
new Employees("李三",20,10000),
new Employees("王三",30,15000)
);
@Test
public void show() {
employees.stream()
.map((x)->x.getAge())
.forEach(System.out::println);
}
}
flagmap 接受一个函数作为参数 将流中的每个值转换成一个流 然后把所有流链接成一个流
package com.lijiawei;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class TestLamda{
@Test
public void show() {
List<String> list = Arrays.asList("aa","bb","cc");
Stream<Character> s = list.stream()
.flatMap(TestLamda::get);
s.forEach(System.out::print);
}
public static Stream get(String str){
List l = new ArrayList();
for (Character c : str.toCharArray()){
l.add(c);
}return l.stream();
}
}
map和flagmap的对比:map好比集合里添加了一个集合 flagmap好比 把集合中的元素添加到另一个集合
map 对每一个元素都看做一个流 处理完之后在把这些流放到一个流里Stream<Stream>
flagmap把所有元素都处理完放到一个流里Stream
排序
sorted() 自然排序 Comparable
sorted(Comparator) 自定义排序 Comparator
package com.lijiawei;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class TestLamda{
@Test
public void show() {
List<String> list = Arrays.asList("c","bb","d");
list.stream()
.sorted()
.forEach((x)->System.out.println(x));
}
}
查找与匹配
package com.lijiawei;
import org.junit.Test;
import javax.swing.text.html.Option;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class TestLamda{
List<Employees> employees = Arrays.asList(
new Employees("张三",18,5000),
new Employees("asd三",18,5000),
new Employees("张das三",18,5000),
new Employees("李三",20,10000),
new Employees("王三",30,15000)
);
@Test
public void show() {
//判断名字是否都是张三 allMatch
Boolean s = employees.stream()
.allMatch((e)->e.getName().equals("张三"));
System.out.println(s);
}
@Test
public void show1() {
//判断是否有名字是张三 anyMatch
Boolean s = employees.stream()
.anyMatch((e)->e.getName().equals("张三"));
System.out.println(s);
}
@Test
public void show2() {
//判断是否没有名字是张三 noneMatch
Boolean s = employees.stream()
.noneMatch((e)->e.getName().equals("张三"));
System.out.println(s);
}
@Test
public void show3() {
//返回第一个元素 findFirst
Optional s = employees.stream()
.findFirst();
System.out.println(s.get());
}
@Test
//返回当前流中的任意元素
public void show4() {
//返回第一个元素 findFirst ///parallelStream并行流
Optional s = employees.parallelStream()
.filter((x)->x.getAge()==18)
.findAny();
System.out.println(s);
}
@Test
public void show5() {
//count 获取流中有多好元素
long s = employees.parallelStream()
.count();
System.out.println(s);
}
@Test
public void show6() {
//count 获取流中有多好元素
Optional s = employees.parallelStream()
.max((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()));
System.out.println(s.get());
}
}
规约与收集
package com.lijiawei;
import org.junit.Test;
import javax.swing.text.html.Option;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestLamda{
List<Employees> employees = Arrays.asList(
new Employees("张三",18,5000),
new Employees("asd三",18,5000),
new Employees("张das三",18,5000),
new Employees("李三",20,10000),
new Employees("王三",30,15000)
);
@Test
public void show() {
//规约简单实用
//指定初始值为0 0+x(1) x=1 y=2 x=3 =4 x=7 y=5..........
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
Integer in =list.stream().reduce(0,(x,y)->x+y);
System.out.println(in);
}
@Test
public void show1() {
//mapreduce
Optional o =employees.stream()
.map(Employees::getSalary)
.reduce(Double::sum);
System.out.println(o.get());
}
@Test
public void show2() {
//收集 取出集合所有名字并添加到list集合
List<String> s =employees.stream()
.map(Employees::getName)
.collect(Collectors.toList());
System.out.println(s);
}
@Test
public void show3() {
//收集 取出集合所有名字并添加到其他集合 比如linkedlist
LinkedHashSet<String> s =employees.stream()
.map(Employees::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
System.out.println(s);
}
}
并行流与顺序流
package com.lijiawei;
import org.junit.Test;
import java.util.stream.LongStream;
public class TestLamda{
@Test
public void show() {
//0到1千亿累加和
Long start = System.currentTimeMillis();
LongStream.rangeClosed(0,100000000000L)
//并行
.parallel()
//累加
.reduce(0,Long::sum);
Long end = System.currentTimeMillis();
System.out.println(start-end);
}
}
接口中的方法
当有类实现这个接口的时候 可以不重写 接口中的默认方法
package com.lijiawei;
public interface My {
//默认方法
default public void show(){
System.out.println("你不好");
//静态方法
public static void show(){
System.out.println("你不好");
}
}
注意 1 当 A 类实现一个B接口 并继承一个C类 并且B和C有相同的方法时 优先使用类的 方法
注意2 当A类同时实现了B和C接口 B和C有相同的默认方法 那就必须指定重写方法
package com.lijiawei;
public class Test implements My,Employees{
@Override
public String show() {
return Employees.super.show();
}
}