JDK8新特性第一章

1、lambda表达式

在这里插入图片描述
在这里插入图片描述

 //lambda完成集合遍历
 	 list.forEach(value-> System.out.println(value+","));
 //lambda改造匿名内部类使用
     Runnable runnable1 = ()-> System.out.println("hello itheima lambda");
 //lambda完成集合排序
     Arrays.sort(language,(o1,o2)->o1.compareTo(o2));
查看内部类里面的内容,可以在lambda表达式执行之前,添加
	System.setProperty("jdk.internal.lambda.dumpProxyClasses", "D://");
这个方法会将运行时生成的内部类class文件进行输出。当该文件生成后,可以通过 javap -c -p class文件名 查看文件中的内容

Lambda使用外部定义变量
	public void demo(){
	  int port = 8086;
	  Runnable runnable = ()-> System.out.println(port);
	}
在这段代码中,在Lambda表达式内部引用了外部变量。但是当在Lambda方法体内使用外部变量时,其必须声明为final。
上述代码虽然没有显示的声明,但是在Java8它自动的会对需要为final的变量进行转换。

在这里插入图片描述

2、函数式接口

有且只有一个抽象方法的普通接口,如果声明多个抽象方法则会报错。
但是默认方法和静态方法在此接口中可以定义多个。
在这里插入图片描述
在Java8的类库设计中,已经引入了几个函数式接口:

1、Predicate数据判断
   public static List<Student> filter(List<Student> studentList, Predicate<Student> predicate){
        List<Student> list = new ArrayList<>();
        studentList.forEach(s->{
            if (predicate.test(s)){
                list.add(s);
            }
        });
        return list;
    }
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(1,"张三","M"));
        students.add(new Student(2,"李四","M"));
        students.add(new Student(3,"王五","F"));

        List<Student> result = filter(students, (s) -> s.getSex().equals("F"));
        System.out.println(result.toString());
    }
2、Consumer获取数据,方法没返回。
public class MyConsumerDemo {
    public static void foreach(List<String> list, Consumer<String> consumer){
        list.forEach(v->consumer.accept(v));
    }
    public static void main(String[] args) {
        List<String> arrays = new ArrayList<>();
        arrays.add("java");
        foreach(arrays,(s)-> System.out.println(s+","));
    }
}
3、Function数据类型转换
public class MyFunctionDemo {
    public static Integer convert(String value, Function<String,Integer> function){
        return function.apply(value);
    }
    public static void main(String[] args) {
        String value ="666";
        Integer result = convert(value, (s) -> Integer.parseInt(value) + 222);
        System.out.println(result);
    }
}
4、Supplier获取数据,并且方法有返回。
public static Integer getMin(Supplier<Integer> supplier){
        return supplier.get();
    }
    public static void main(String[] args) {
        int[] arr = {100,20,50,30,99,101,-50};
        Integer result = getMin(() -> {
            int min = arr[0];
            for (int i : arr) {
                if (i < min) {
                    min = i;
                }
            }
            return min;
        });
        System.out.println(result);
    }

3、Stream常用函数

常用函数
  Stream<Object> objectStream = Stream.of("1", 2, true, new St());
  Integer[] numbers = new Integer[]{1,2,3,4,5,6};
  Stream<Integer> stream = Arrays.stream(numbers);

String数组转Int数组
String[] orgArray =a;
int[] orgIds = Arrays.stream(a).mapToInt(Integer::valueOf).toArray();

 List<String> result = list.stream() .filter(s -> s.getAge() < 20) 
 .sorted(Comparator.comparing(Student::getAge)).map(Student::getName) 
 .collect(Collectors.toList()).distinct().limit(3).skip(2).findFirst();
 distinct:去空对象集合,需要重写hashcode、equals方法。
 findAny用于获取流中随机的某一个元素,findAny对于同一数据源的多次操作会返回不同的结果。但是,
   我们现在的操作是串行的,所以在数据较少的情况下,一般会返回第一个结果,但是如果在并行的情况
   下,那就不能确保返回的是第一个了
 .map(Student::getName).map(String::length) //也可以继续向下获取每一个名称的长度
集合元素拼接
   拼接符可有可无
   String collect = studentList.stream().map(Student::getName).collect(Collectors.joining(","));
合并流
   Stream.concat(s1,s2).map(name->new Person(name)).forEach(p-> System.out.println(p));
对集合排序
   students.sort((s1,s2)->s1.getId().compareTo(s2.getId()));
   Comparator<Student> comparator = Comparator.comparing((Student s) -> s.getId());
   list.sort(Comparator.comparing((s)->s.getId()));
   list.sort(Comparator.comparing(Student::getId));

全部匹配
	list.stream().allMatch(Student::getIsPass)
至少有一个匹配
    list.stream().anyMatch(s->s.getAge()<20)
集合总数统计
	Long collect =list.stream().collect(Collectors.counting());
	long count = studentList.stream().count(); 
	
根据年龄进行分组,获取并汇总人数
    Map<Integer, Long> collect = studentList.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.counting()));
分组
    Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getSex));
根据年龄和是否通过分组
	Map<Integer, Map<String, List<Student>>> collect =studentList.stream().collect(Collectors.group
		ingBy(Student::getAge,Collectors.groupingBy(student -> {
		  if (student.getIsPass()) {
		    return "pass";
		 } else {
		    return "not pass";
		 }
		})));
根据年龄与是否及格进行分组,并汇总人数
   Map<Integer, Map<Boolean, Long>> collect = studentList.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.groupingBy(Student::getIsPass, Collectors.counting())));

根据年龄与是否通过进行分组,并获取每组中分数最高的学生
 Map<Integer, Map<Boolean, Student>> collect = studentList.stream().collect(
    Collectors.groupingBy(Student::getAge,
       Collectors.groupingBy(Student::getIsPass,
          Collectors.collectingAndThen(
              Collectors.maxBy(
                Comparator.comparing(Student::getScore)
                 ), Optional::get
      )))
 );

最大最小值获取
	没优化前:
    Optional<Student> optional=studentList.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge)));
    优化后:max-min
    Optional<Student> min = studentList.stream().min(Comparator.comparing(Student::getAge));
        if (min.isPresent()){
            System.out.println(min.get());
        }
集合中值相加
    Integer collect = studentList.stream().collect(Collectors.summingInt(Student::getAge));
    上边优化后:
    int sum = studentList.stream().mapToInt(Student::getAge).sum();
    int sum = numbers.parallelStream().mapToInt(i ->i).sum();
集合中平均值计算
    Double collect1 = studentList.stream().collect(Collectors.averagingInt(Student::getAge));
    这种方式虽然代码写多了一些,但是可以防止空值的出现:
    OptionalDouble average = studentList.stream().mapToDouble(Student::getAge).average();
        if (average.isPresent()){
            System.out.println(average.getAsDouble());
        }
集合函数计算(长度、总和、最大最小、平均值)
  IntSummaryStatistics collect = studentList.stream().collect(Collectors.summarizingInt(Student::getAge));
  long count = collect.getCount();
  long sum = collect.getSum();
  int max = collect.getMax();
  int min = collect.getMin();
  double average = collect.getAverage();
    }
    
获取所有的文件列表信息和文件中的内容
   Files.list(Paths.get("D:\\workspace")).forEach(path-> {
        System.out.println(path);
        //读取每一个文件中的内容信息
        try {
             Files.lines(path).forEach(content-> System.out.println(content));
        } catch (IOException e) {
           e.printStackTrace();
        }
});

初始值是0,每次拿集合中的2个数相加
	Integer reduce = numbers.stream().reduce(0, (a, b) -> a + b);
	Integer reduce = numbers.stream().reduce(0, Integer::sum);
	Optional<Integer> optional = numbers.stream().reduce(Integer::sum);
        if (optional.isPresent()){
            Integer integer = optional.get();
            System.out.println(integer);
        }
获取最大、最小值
  Optional<Integer> maxOptional = numbers.stream().reduce(Integer::max);
  Optional<Integer> maxOptional = numbers.stream().max(Integer::compareTo);
  Optional<Integer> minOptional = numbers.stream().min(Integer::compareTo);
     if (maxOptional.isPresent()){
          System.out.println(maxOptional.get());
     }

并行流介绍

 stream():串行流
 parallelStream():并行流,在核数多等业务情况下效率高
 findAny串行流且数据较少时,获取的结果一般为流中第一个元素,但是当为并流行的时候,则会随机获取
 List<Student> result = list.parallelStream().filter(Student::getIsPass).findAny().collect(Collectors.toList());
 
 使用注意事项
	 对于并行流,一定不要陷入一个误区:并行一定比串行快。并行在不同的情况下它不一定是比串行快的。影响并行流性能主要存在5个因素:
	  1)数据大小:输入数据的大小,直接影响了并行处理的性能。因为在并行内部实现中涉及到了fork/join操作,它本身就存在性能上的开销。
	    因此只有当数据量很大,使用并行处理才有意义。
	  2)源数据结构:fork时会对源数据进行分割,数据源的特性直接影响了fork的性能。
	    ArrayList、数组或IntStream.range,可分解性最佳,因为他们都支持随机读取,因此可以被任意分割。
		HashSet、TreeSet,可分解性一般,其虽然可被分解,但因为其内部数据结构,很难被平均分解。
		LinkedList、Streams.iterate、BufferedReader.lines,可分解性极差,因为他们长度未知,无法确定在哪里进行分割。
	  3)装箱拆箱:尽量使用基本数据类型,避免装箱拆箱。
	  4)CPU核数:fork的产生数量是与可用CPU核数相关,可用的核数越多,获取的性能提升就会越大。
	  5)单元处理开销:花在流中每个元素的时间越长,并行操作带来的性能提升就会越明显。

性能测试
	通过基本类型、对象类型和复杂对象来对普通for循环、串行流和并行流进行分别的性能测试
	此处使用常见线上服务器配置。12核24线程,96G内存的配置。
	数据量是1*10的6次方以上测试结果:
	1、对于基本数据类型Stream串行的性能开销是普通for循环的两倍左右。同时Stream并行的性能比普通for循环和串行都要好。
	2、当操作对象类型时,Stream串行的性能开销仍高于普通for循环一倍左右。同时Stream并行的性能比普通for循环和串行都要好。
	3、当操作复杂对象时,普通for循环的性能开销会高于Stream串行,同时仍然是Stream并行性能最优

4、接口

类实现接口规则
普通方法必须实现,默认方法可以选择性重写,静态方法无法重写。

1、接口中可以定义多个默认方法,并且可以有方法体自己实现。调用接口中默认方法用对象.默认方法名
2、接口中可以定义多个静态方法,调用接口中静态方法用接口.静态方法名。
//抽象方法
	String abstractMethod();
//默认方法
    default String defaultMethod(){
       return "execute default method";
    }
//静态方法
    static String staticMethod(){
      return "execute static method";
    }

在这里插入图片描述

5、方法引用

 使用语法
 	类名或实例名::方法名

6、自定义收集器

/**
 * 自定义收集器返回所有合格的学员
 */
public class MyCollector implements Collector<Student, List<Student>,List<Student>> {
    @Override
    public Supplier<List<Student>> supplier() {
        return ArrayList::new;
    }
    @Override
    public BiConsumer<List<Student>, Student> accumulator() {
        return ((studentList, student) -> {
            if (student.getIsPass()){
                studentList.add(student);
            }
        });
    }
    @Override
    public BinaryOperator<List<Student>> combiner() {
        return null;
    }
    @Override
    public Function<List<Student>, List<Student>> finisher() {
        return Function.identity();
    }
    @Override
    public Set<Characteristics> characteristics() {
        return EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED);
    }
}

使用
 public static void main(String[] args) {
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(3,"王五","F",21,true));
        studentList.add(new Student(1,"张三","M",19,true));
        studentList.add(new Student(4,"赵六","F",20,false));
        studentList.add(new Student(2,"李四","M",18,true));

        List<Student> list = studentList.stream().collect(new MyCollector());
        System.out.println(list);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值