Java8新特性 Note [vaynexiao]

lambda由来

public class Lamda {
    
    
    //方式2 静态内部类
    static class Cat2 implements Animal{
    
    
        @Override
        public void say(int a) {
    
    
            System.out.println("cat 静态内部类 ......"+a);
        }
    }
    public static void main(String[] args) {
    
    
        Animal c1 = new Cat(); // 注意:多态
        c1.say(111);

        Cat2 c2 = new Cat2();
        c2.say(222);

        //方式3 局部内部类
        class Cat3 implements Animal{
    
    
            @Override
            public void say(int a) {
    
    
                System.out.println("cat 局部内部类 ......"+a);
            }
        }
        Cat3 c3 = new Cat3();
        c3.say(333);

        //方式4 匿名内部类
        Animal c4 = new Animal(){
    
      // 注意:匿名内部类new的是接口
            @Override
            public void say(int a) {
    
    
                System.out.println("cat 匿名内部类 ......"+a);
            }
        };
        c4.say(444);

        //方式5 lamda方式
        c1 = (a)->{
    
    
            System.out.println("cat lamda方式 ......"+a);
        };
        c1.say(555);

    }
}

interface Animal {
    
    
    void say(int a);
}
//方式1 同级类
class Cat implements Animal{
    
    
    @Override
    public void say(int a) {
    
    
        System.out.println("cat 同级类 ......"+a);
    }
}

函数式接口

简单用法

Java8中引入了一个新的操作符 "->" 
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体

/* 
* 语法格式一:无参数,无返回值
* 		() -> System.out.println("Hello");
* 语法格式二:有一个参数,并且无返回值
* 		(x) -> System.out.println(x)
* 语法格式三:若只有一个参数,小括号可以省略不写
* 		x -> System.out.println(x)
* 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
*		Comparator<Integer> com = (x, y) -> {
*			System.out.println("函数式接口");
*			return Integer.compare(x, y);
*		};
* 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
* 		Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
* 语法格式六:参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
* 		(Integer x, Integer y) -> Integer.compare(x, y);
*/

/
        /**
         * (1)参数列表 (2)-> (3)lambda体,如上面例子中的
         * i -> System.out.println(i))
         *
         * 左边是参数列表,lambda可以接收任意多个参数,当参数数量大于1时,需要将参数括起来,如
         * (i,j)->System.out.println(i+j))
         *
         * 如果不需要指定参数,需要使用()来表示无参,如
         * ()->System.out.println("hello lambda")
         *
         * 可以看到我们并没有声明参数的数据类型,这是因为很多情况下,编译器能从上下文中推导出数据的参数类型,当然我们可以显示的指定类型
         * (int i,int j)->System.out.println(i+j))
         *
         * 函数箭头的右侧是lambda体,上面的例子中只有一行代码,当有多行代码时,需要使用{}括起来,如
         * (i,j) ->{System.out.println(i);System.out.println("----"); }
         *
         * 如果lambda体中的表达式有返回值,需要使用return来返回,也可以后面跟一个参数来中止lambda体,
         * (i,j)->return i+j  或 (i,j)->i+j;
         */
Lambda 表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 
给类加@FunctionalInterface可以检查是否是函数式接口

4大核心函数式接口

/*
 * Java8 内置的四大核心函数式接口
 *
 * Consumer<T> : 消费型接口
 * 		void accept(T t);
 *
 * Supplier<T> : 供给型接口
 * 		T get();
 *
 * Function<T, R> : 函数型接口
 * 		R apply(T t);
 *
 * Predicate<T> : 断言型接口
 * 		boolean test(T t);
 */
public class FourCoreFunctionInterface {
    
    

    //Predicate<T> 断言型接口:
    @Test
    public void test4(){
    
     //将满足条件的字符串,放入集合中
        List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
        List<String> strList = filterStr(list, (s) -> s.length() > 3);
        for (String str : strList) {
    
    
            System.out.println(str);
        }
    }
    public List<String> filterStr(List<String> list, Predicate<String> pre){
    
    
        List<String> strList = new ArrayList<>();
        for (String str : list) {
    
    
            if(pre.test(str)){
    
    
                strList.add(str);
            }
        }
        return strList;
    }

    //Function<T, R> 函数型接口:
    @Test
    public void test3(){
    
     //用于处理字符串
        String newStr = strHandler(" 我威武   ", (str) -> str.trim());
        System.out.println(newStr);

        String subStr = strHandler("我大尚硅谷威武", (str) -> str.substring(2, 5));
        System.out.println(subStr);
    }
    public String strHandler(String str, Function<String, String> fun){
    
    
        return fun.apply(str);
    }

    //Supplier<T> 供给型接口 :
    @Test
    public void test2(){
    
     //产生指定个数的整数,并放入集合中
        List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
        for (Integer num : numList) {
    
    
            System.out.println(num);
        }
    }
    public List<Integer> getNumList(int num, Supplier<Integer> sup){
    
    
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
    
    
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }

    //Consumer<T> 消费型接口 :
    @Test
    public void test1(){
    
     //打印一句话
        happy(10000, (m) -> System.out.println("一个数字:" + m));
    }
    public void happy(double money, Consumer<Double> con){
    
    
        con.accept(money);
    }
}

stream parallelStream

Integer[] array = new Integer[]{
    
    1, 2, 3, 4, 5};
Arrays.asList(array).stream().forEach(i -> {
    
    
    System.out.println(Thread.currentThread().getName() + " num:" + i);
}); 
//main num:1
//main num:2
//main num:3
//main num:4
//main num:5

//改为parallelStream
Integer[] array = new Integer[]{
    
    1, 2, 3, 4, 5};
Arrays.asList(array).parallelStream().forEach(i -> {
    
    
    System.out.println(Thread.currentThread().getName() + " num:" + i);
});
//会创建多个线程,同时处理逻辑
//main num:3
//ForkJoinPool.commonPool-worker-5 num:4
//main num:5
//ForkJoinPool.commonPool-worker-3 num:2
//ForkJoinPool.commonPool-worker-5 num:1

//ArrayList线程不安全,并行流处理时很可能空指针异常,或者list长度不等于1000
//改为线程安全的Vector即可
List<Integer> list = new ArrayList<>();
IntStream.rangeClosed(1, 1000).parallel().forEach(i -> list.add(i));
System.out.println(list.size());
  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。

(stream是串行流,适合存在线程安全问题 阻塞任务 重量级任务 同一事务的逻辑任务。
parallelstream是并行流,适合没有线程安全 单纯的数据处理逻辑任务。因为并行,当然速度比普通for和stream快很多,特别是有数据库操作时)

 * 1. 创建Stream
 * 2. 中间操作
 * 3. 终止操作

方法引用与构造器引用

 /* 一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用
 * 			  (可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
 * 1. 对象的引用 :: 实例方法名
 * 2. 类名 :: 静态方法名
 * 3. 类名 :: 实例方法名
 * 注意:
 * 	 ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
 * 	 ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,
 		第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
 *
 * 二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!
 * 1. 类名 :: new
 *
 * 三、数组引用
 * 	类型[] :: new;
 */

List emps

List<Employee> emps = Arrays.asList(
    new Employee(102, "李四", 79, 6666.66, Employee.Status.BUSY),
    new Employee(101, "张三", 18, 9999.99, Employee.Status.FREE),
    new Employee(103, "王五", 28, 3333.33, Employee.Status.VOCATION),
    new Employee(104, "赵六", 8, 7777.77, Employee.Status.BUSY),
    new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE),
    new Employee(104, "赵六", 8, 7777.77, Employee.Status.FREE),
    new Employee(105, "田七", 38, 5555.55, Employee.Status.BUSY)
);

创建Stream

//1. Collection 提供了两个方法  stream() 与 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

//2. 通过 Arrays 中的 stream() 获取一个数组流
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);

//3. 通过 Stream 类中静态方法 of()
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);

//4. 创建无限流
//迭代
Stream<Integer> stream3 = Stream.iterate(2, (x) -> x*2).limit(5);
stream3.forEach(System.out::println);// 2 4 8 16 32

//生成
Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
stream4.forEach(System.out::println);

中间操作

// filter
Stream<Employee> stream = emps.stream()
    .filter((e) -> {
    
    
        System.out.println("测试中间操作");
        return e.getAge() <= 35;
    })
    .limit(3)
    .forEach(System.out::println);
;
//.filter((e) -> e.getAge() == 38 );//语句只有一行时的省略写法
stream.forEach(System.out::println);

// limit  skip  forEach
emps.stream()
    .filter((e) -> {
    
    
        System.out.println("短路!"); // &&  ||
        return e.getSalary() >= 5000;
    }).limit(3).skip(1)
    .forEach(System.out::println);

// distinct 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素。所以Entity这俩方法必须编写
emps.stream()
    .distinct()
    .forEach(System.out::println);

终止操作

简单操作

//allMatch——检查是否匹配所有元素
boolean bl = emps.stream().allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

//anyMatch——检查是否至少匹配一个元素
boolean bl1 = emps.stream().anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

//noneMatch——检查是否没有匹配的元素
boolean bl2 = emps.stream().noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));

//findFirst——返回第一个元素
Optional<Employee> op = emps.stream()
    .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
    .findFirst();
System.out.println(op.get());

//findAny——返回当前流中的任意元素
Optional<Employee> op2 = emps.parallelStream()
    .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
    .findAny();
System.out.println(op2.get());

//count——返回流中元素的总个数
long count = emps.stream()
    .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
    .count(); //3
System.out.println(count);

//max——返回流中最大值
Optional<Double> opm = emps.stream()
    .map(Employee::getSalary)
    .max(Double::compare);//9999.99
System.out.println(opm.get());

//min——返回流中最小值
Optional<Employee> op3 = emps.stream()
    .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
//vo.Employee [id=103, name=王五, age=28, salary=3333.33, status=VOCATION]

map

.map((e) -> e.getName());
.map(String::toUpperCase);

// .map(类名 -> 方法名);
public static Stream<Character> filterCharacter(String str){
    
    
    List<Character> list = new ArrayList<>();
    for (Character ch : str.toCharArray()) {
    
    
        list.add(ch);
    }
    return list.stream();
}
//map 
Stream<Stream<Character>> stream2 = strList.stream()//stream 中也是stream
    .map(TestStreamAPI1::filterCharacter);
stream2.forEach((sm) -> {
    
    
    sm.forEach(System.out::println);
});
//flagMap 平铺(元素中元素也会全部拿出来)
Stream<Character> stream3 = strList.stream()
    .flatMap(TestStreamAPI1::filterCharacter);
stream3.forEach(System.out::println);

sort

emps.stream()
    .map(Employee::getName)
    .sorted()
    .forEach(System.out::println);


emps.stream()
    .sorted((x, y) -> {
    
    
        if(x.getAge() == y.getAge()){
    
    
            return x.getName().compareTo(y.getName());
        }else{
    
    
            return Integer.compare(x.getAge(), y.getAge());
        }
    }).forEach(System.out::println);

.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
    
.sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))

collect

//toList
List<String> list = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
//toSet
Set<String> set = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
//HashSet
HashSet<String> hs = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
Optional<Double> max = emps.stream()
    .map(Employee::getSalary)
    .collect(Collectors.maxBy(Double::compare));//使用Double的compare方法,找到max
System.out.println("max: "+max.get());

Optional<Employee> op = emps.stream()
    .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println("min emp: "+op.get());

Double sum = emps.stream()
    .collect(Collectors.summingDouble(Employee::getSalary));
//还有 summingDouble summarizingLong summarizingInt
//.collect(Collectors.averagingDouble(Employee::getSalary));
//.collect(Collectors.counting());

DoubleSummaryStatistics summaryStatistics = emps.stream()
    .collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println( "summaryStatistics: "+summaryStatistics);
//DoubleSummaryStatistics{count=7, sum=48888.840000, min=3333.330000, average=6984.120000, max=9999.990000}
//这里有精度问题
//还有 IntSummaryStatistics LongSummaryStatistics

//groupingBy
Map<Employee.Status, List<Employee>> map = emps.stream()
	.collect(Collectors.groupingBy(Employee::getStatus));

Map<Employee.Status, Map<String, List<Employee>>> map = emps.stream()
    .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
    
    
        if(e.getAge() >= 60)
            return "老年";
        else if(e.getAge() >= 35)
            return "中年";
        else
            return "成年";
    })));
System.out.println(map);

Map<Boolean, List<Employee>> map = emps.stream()
    .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
System.out.println(map);//false区 true区

String str = emps.stream()
	.map(Employee::getName)
	.collect(Collectors.joining("," , "----", "----"));//join三个重载方法:无参 单参 3参

Optional<Double> sum = emps.stream()
	.map(Employee::getSalary)
	.collect(Collectors.reducing(Double::sum));

forEach

set.forEach(System.out::println);

reduce

// 归约 
// 常用重载方法,差一个起始值T identity     reduce(T identity,BinaryOperator)/reduce(BinaryOperator) 
// 可以将流中元素反复结合起来,得到一个值。
@Test
public void test1(){
    
    
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    Integer sum = list.stream()
        // .reduce("", String::concat);
        // 给一个起始值,然后再取前2元素进行String的concat方法
        //合并成一个元素,再取前2各元素重复concat方法
        .reduce(0, (x, y) -> x + y); 
    System.out.println(sum);

    Optional<Double> op = emps.stream()
        .map(Employee::getSalary)
        .reduce(Double::sum);//使用Double的静态方法sum
    	//.reduce(Integer::sum);
    System.out.println(op.get());
}

//ifPresent 如果有元素,执行System.out的println
Stream<Integer> stream = Arrays.stream(new Integer[]{
    
    1, 2, 3, 4, 5, 6, 7, 8});
stream = Arrays.stream(new Integer[]{
    
    1, 2, 3, 4, 5, 6, 7});
//求和
stream.reduce((i, j) -> i + j).ifPresent(System.out::println);

Optional

 * 一、Optional 容器类:用于尽量避免空指针异常
 * 	Optional.of(T t) : 创建一个 Optional 实例
 * 	Optional.empty() : 创建一个空的 Optional 实例
 * 	Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
 * 	isPresent() : 判断是否包含值
 * 	orElse(T t) :  如果调用对象包含值,返回该值,否则返回t
 * 	orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
 * 	map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
 * 	flatMap(Function mapper):与 map 类似,要求返回值必须是Optional

实战

        //List<String>
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
        long count = strings.stream().filter(string -> string.isEmpty()).count();
        System.out.println("空字符串数量为: " + count);
        count = strings.stream().filter(string -> string.length() == 3).count();
        System.out.println("字符串长度为3的数量为: " + count);
        List<String> filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
        System.out.println("删除空字符串后的list列表: " + filtered);
        String mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
        System.out.println("删除空字符串,并使用逗号把它们合并为String: " + mergedString);
        count = strings.parallelStream().filter(string -> string.isEmpty()).count();
        System.out.println("并行处理  空字符串的数量为: " + count);

        //List<Integer>
        List<Integer> integers = Arrays.asList(1, 2, 13, 4, 15, 6, 17, 8, 19);
        System.out.println("平方数列表: " + integers.stream().map( i ->i*i).distinct().collect(Collectors.toList()));
        IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());

        //Integer[]
        Integer[] nums = new Integer[]{
    
    1,2,3,4,5}; // 求平方
        Arrays.stream(nums).map((x) -> x*x).forEach(System.out::println);

        //Random ints()
        System.out.println("输出10个随机数: ");
        Random random = new Random();
        random.ints().limit(10).sorted().forEach(System.out::println);

        //String[]
        String[] pp = {
    
    "Mike", "Bob",  "lily",  "David", "Andy"};
        List<String> players =  Arrays.asList(pp);
        players.forEach((player) -> System.out.print(player + "; "));

        //String[]
        String[] names = {
    
    "aa", "cc",  "dd",  "ff", "gg"};
        Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));
        Arrays.sort(names, sortByName);
        System.out.println(names.toString());




public class  UserVO {
    
    
    private Integer id;
    private String name;
    private String email;
    //...
}
UserVO user1 = new UserVO(1, "小明", "小明qq.com");
UserVO user2 = new UserVO(2, "小芳", "小芳qq.com");
UserVO user3 = new UserVO(3, "小华", "小华qq.com");
UserVO user4 = new UserVO(4, "小华", "小华qq.com");
List<UserVO> userVOList = Arrays.asList(user1, user2, user3, user4);

// filter 同时根据两个条件过滤成员
List<UserVO> filterList = userVOList.stream()
    .filter( person -> ("小芳".equals(person.getName()) && person.getId()<3) )
    .collect(Collectors.toList());

// filter 遍历每个成员,转为List
List<String> num = Arrays.asList("1","2","33","tt","阿萨德");
List<String> collect1 = num.stream().map(n -> n+"-go")
    .filter(r -> r.length()>4)
    .collect(Collectors.toList()); //[33-go, tt-go, 阿萨德-go]

List<String> list = userVOList.stream().map(UserVO::getName).collect(Collectors.toList());
// UserVO::getName  等价于   u -> u.getName() 或者 u -> { xxxxxxx }
// :: 只能取出属性值 -> 可以跟语句,更加强大

// 提取为map对象
// 生成一对一映射,类似for循环作用
// 下面  (o, n) -> o表示的 如果出现重复key,则用 原来代替新的key o,此处o old n new
// 如果不设置 (o, n)  当出现重复key时:就会报错 IllegalStateException: key value
Map<String, String> map = userVOList.stream()
    .collect(Collectors.toMap(UserVO::getName, UserVO::getEmail, (o, n) -> o));
for (Map.Entry<String, String> entry : map.entrySet()) {
    
    
    System.out.println("提取为map对象:  "+entry.getKey()+"---"+entry.getValue());
}

// 使用groupingBy转为固定数据格式:map<String,List<String>>
// 分组条件的字段作为map的key,分组后每组的对象合并为一个List<T>
Map<String, List<UserVO>> map2 = userVOList.stream()
    .collect(Collectors.groupingBy(UserVO::getEmail));
for (Map.Entry<String, List<UserVO>> entry : map2.entrySet()) {
    
    
    System.out.println("转为map<String,List<String>>:  "+entry.getKey()+":"+entry.getValue());
}

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();

猜你喜欢

转载自blog.csdn.net/vayne_xiao/article/details/110706179