IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java基础(五)Lambda表达式、Stream流 -> 正文阅读

[Java知识库]Java基础(五)Lambda表达式、Stream流

??本系列文章:
????Java基础(一)基本数据类型、变量类型、修饰符、表达式、数组、Math类、分支循环、关键字、调用方式、JVM/JDK与JRE
????Java基础(二)字符串、Java常用包、四种引用、内存泄漏、深克隆与浅克隆、语法糖、IO
????Java基础(三)面向对象、类和对象、封装继承多态、重写和重载、构造方法、内部类、包装类、对象实例化的四种方式
????Java基础(四)异常、final/finally/finalize、可变参数、枚举、日期、反射、泛型
????Java基础(五)Lambda表达式、Stream

一、Lambda表达式

1.1 Lambda语法

?Lambda表达式是 Java8 中最重要的新功能之一。使用 Lambda 表达式可以替代只有一个抽象函数的接口实现,可以替代匿名内部类,代码看起来更简洁易懂。Lambda表达式同时还提升了对集合的迭代、遍历、过滤数据的操作。
?Lambda 表达式的语法:

(parameters) -> expression
或
(parameters) ->{ statements; }

?Lambda表达式的重要特征:

1、可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
2、可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
3、可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
4、可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。

?看一些简单的例子:

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

?Lambda表达式应用场景:任何有函数式接口的地方。只有一个抽象方法(Object 类中的方法除外)的接口是函数式接口。就像Runnable接口中,只有一个run方法。

1.2 Lambda使用

1.2.1 Runnable

?最常见的匿名内部类之一应该就是Runnable,在JDK1.8之前要这样写:

        new Thread(new Runnable() {
            public void run() {
                System.out.println("The runable  is using!");
            }
        }).start();

?在JDK1.8之后可以使用lambda表达式:

	//It's a lambda function
	new Thread(() -> System.out.println("It's a lambda function")).start();

1.2.2 排序

?再看个例子,对集合元素进行排序:

        List<String> list = Arrays.asList("java","javascript","scala","python");
        //before java8
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        });
        for(String str:list){
            System.out.println(str);
        }
        //after java8
        Collections.sort(list,(a,b)->a.length()-b.length());

1.2.3 遍历

?遍历集合中的元素也是 lambda表达式的常见场景之一,示例:

        List<String> languages = Arrays.asList("Java","Python","C++");
        //before java8
        for(String language:languages) {
            System.out.println(language);
        }
        //after java8
        languages.forEach(x -> System.out.println(x));

1.2.4 过滤

?用 lambda表达式充当过滤条件,筛选出一部分元素,也是常见的操作。示例:

/*实体类*/
public class Student {
    private String name;
    private int age;
    private int score;

    public Student() {
    }

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {  return name; }

    public void setName(String name) {  this.name = name; }

    public int getAge() { return age; }

    public void setAge(int age) {   this.age = age; }

    public int getScore() {  return score; }

    public void setScore(int score) {   this.score = score;  }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

/*过滤接口*/
public interface StudentFilter {
    boolean compare(Student student);
}

/*客户端*/
public class Test {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<Student>();
        list.add(new Student("zhangsan",14,67));
        list.add(new Student("lisi",13,89));
        list.add(new Student("wangwu",15,97));
        list.add(new Student("maliu",12,63));
        list.add(new Student("zhaoqi",17,75));

        getByFilter(list,(e)->e.getAge()>14 );
        getByFilter(list, (e)->e.getScore()>75);
        System.out.println("-------------------");
        getByFilter(list, (e)->e.getName().length()>5);
    }

    public static void getByFilter(ArrayList<Student> students, StudentFilter filter){
        ArrayList<Student> list = new ArrayList<>();
        for(Student student:students){
            if(filter.compare(student)){
                list.add(student);
            }
        }
        printStudent(list);
    }

    public static void printStudent(ArrayList<Student> students){
        for(Student student:students){
            System.out.println(student);
        }
    }
}

1.3 Lambda表达式的多种写法

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();
        
      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;
        
      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;
        
      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };
        
      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;
        
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      	  System.out.println("Hello " + message);
      // 用括号
      GreetingService greetService2 = (message) ->
      	  System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}

1.4 一些代表输入输出的函数式接口

?Supplier:代表一个输出
?Consumer: 代表一个输入
?BiConsumer :代表两个输入
?Function :代表一个输入,一个输出(一般输入和输出是不同类型的)
?UnaryOperator :代表一个输入,一个输出(输入和输出是相同类型的)
?BiFunction :代表两个输入,一个输出(一般输入和输出是不同类型的)
?BinaryOperator :代表两个输入,一个输出(输入和输出是相同类型的)

  1. 消费(Consumer)型接口:
public void test01(){
    //消费型接口100
    Consumer<Integer> consumer = (x) -> System.out.println("消费型接口" + x);
    consumer.accept(100);
}
  1. 提供(Supplier)型接口
	    List<Integer> list = new ArrayList<>();
	    Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
	    list.add(supplier.get());
	    System.out.println(supplier); //com.test.JavaTest$$Lambda$1/471910020@816f27d
	    for (Integer integer : list) {
	        System.out.println(integer);  //9
	    }
  1. 函数(Function)型接口:
    String oldStr = "abc123456xyz";
    Function<String, String> function = (s) -> s.substring(1, s.length()-1);
    System.out.println(function.apply(oldStr));  //bc123456xy

1.5 Lambda表达式的方法引用

?方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用。
? lambda表达式方法引用的分类:
在这里插入图片描述

  • 1、静态方法引用
    ?如果函数式接口的实现恰好可以通过调用一个静态方法来实现,那么就可以使用静态方法引用。
    ?静态方法引用的lambda写法:
	    Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
	    System.out.println(com1.compare(1, 2));  //-1

	    Comparator<Integer> com2 = Integer::compare;
	    System.out.println(com2.compare(2, 1));   //1
  • 2、实例方法引用
    ?如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用。
    ?实例方法引用的lambda写法:
    //Lambda表达式的形式
    PrintStream ps = System.out;
    Consumer<String> con1 = (s) -> ps.println(s);
    con1.accept("aaa");  //aaa

    //方法引用的形式
    Consumer<String> con2 = ps::println;
    con2.accept("bbb");  //bbb
  • 3、对象方法引用
    ?抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用。
    ?
  • 4、构造方法引用
    ?如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用。
    ?构造器方法引用:
	//lambda表达式形式
    Supplier<List> sup1 = () -> new ArrayList();
    
	//方法引用形式
    Supplier<List> sup2 = ArrayList::new;

???数组构造器方法引用:

interface test {
    public String[] run(int length);
}
 
public class blog {
    public static void main(String[] args) {
   //实质代码:     test t1 = (length) -> new String[length];
        test t2 = String[]::new;
        String[] arr = t2.run(5);
    }
}

???多种构造引用的例子:

public class Test5 {
    public static void main(String[] args) {
        Supplier<Person> s1 = ()->new Person();
        s1.get();   //调用get后才会真正创建对象
        Supplier<Person> s2 = Person::new;
        s2.get();

        Supplier<List> s3 = ArrayList::new;
        Supplier<Set> s4 = HashSet::new;
        Supplier<Thread> s5 = Thread::new;
        Supplier<String> s6 = String::new;

        Consumer<Integer> c1 = (age)->new Account(age);
        Consumer<Integer> c2 = Account::new;
        c1.accept(123);
        c2.accept(456);

        Function<String,Account> f1 = (str)->new Account(str);
        Function<String,Account> f2 = Account::new;
        f1.apply("abc");
        f2.apply("def");

    }
}

class Account{
    public Account(){
        System.out.println("调用无参构造方法");
    }

    public Account(int age){
        System.out.println("age 参数构造" +age);
    }

    public Account(String str){
        System.out.println("str 参数构造" +str);
    }
}

class Person{
    public Person(){
        System.out.println("调用无参的构造方法");
    }
}

二、Stream

2.1 Stream简介

?Stream是一组用来处理数组、集合的API。
? Java 8引入函数式编程,原因有二:

  1. 代码简洁,函数式编程写出的代码简洁且意图明确,使用 stream 接口让你从此告别 for 循环
  2. 多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。

? Stream特性:

  1. 不是数据结构,没有内部存储
  2. 不支持索引访问;
  3. 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算
  4. 支持并行
  5. 很容易生成数组或集合(List,Set);
  6. 支持过滤,查找,转换,汇总,聚合等操作;
  7. 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中(保留意见:毕竟peek方法可以修改流中元素);

? Stream运行机制:
??1)Stream分为 源source,中间操作,终止操作
??2)流的源可以是一个数组、一个集合、一个生成器方法,一个I/O通道等等;
??3)一个流可以有零个和或者多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用。一个流只会有一个终止操作
??4)Stream只有遇到终止操作,它的源才开始执行遍历操作

2.2 Stream的创建

??获取流有以下几种方式。

  • 1、所有的 Collection 集合都可以通过 stream 默认方法获取流
    ??根据Collection获取流, java.util.Collection 接口中加入了default方法 stream 用来获取流,所以其所有实现类均可获取流。示例:
//List集合获取流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//Set集合获取流
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
//Vecter获取流
Vector<String> vector = new Vector<>();
Stream<String> stream3 = vector.stream(); 

??Map 接口不是 Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等情况。示例:

Map<String, String> map = new HashMap<>();

Stream<String> keyStream = map.keySet().stream();

Stream<String> valueStream = map.values().stream();

Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
  • 2、Stream 接口的静态方法 of 可以获取数组对应的流
    ??示例:
String[] array = { "张三", "李四", "王五", "赵六" };
Stream<String> stream = Stream.of(array);
//of 方法的参数其实是一个可变参数,所以支持数组
Stream<String> stream1 = Stream.of(1, 2, 3, 4, 5);

2.3 Stream的中间操作

??Stream的中间操作有如下几种:

1.过滤 filter
2.去重 distinct
3.排序 sorted
4.截取 limit
5.跳跃 skip
6.转换map/flatMap
7.其他 peek

2.3.1 filter

??过滤一些元素,示例:

Arrays.asList(1, 2, 3, 4, 5)
	.stream()
	.filter(x->x%2==0)
	.forEach(System.out::println);

??上述代码的功能是:获取1~5之间的偶数,并输出。结果:

2
4

2.3.2 distinct

??根据元素的 hashCode() 和 equals() 去除重复元素,示例:

Arrays.asList(1,2,3,4,5,6,7,7,7,7)
	.stream()
	.distinct()
	.forEach(System.out::println);

??上述代码的功能是:去除List中的重复数,并输出。结果:

1
2
3
4
5
6
7

2.3.3 sorted

??对集合中的元素排序,顺序是倒序,示例:

Arrays.asList(1,2,3,4,5,6)
	.stream()
	.sorted((a,b)->b-a)
	.forEach(System.out::println);

??结果:

6
5
4
3
2
1

2.3.4 limit

??截断流,使其元素不超过给定数量,示例:

Arrays.asList(1,2,3,4,5,6,7)
	.stream()
	.limit(1)
	.forEach(System.out::println);   //1

??上述代码的功能是:取集合中的第一条数据。

2.3.5 skip

??跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流,示例:

Arrays.asList(1,2,3,3,4,5)
	.stream()
	.skip(1)
	.forEach(System.out::println);

??上述代码的功能是:跳过集合中的第一条数据。结果:

2
3
3
4
5

2.3.6 map

??接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。示例:

	Arrays.asList("1","2","3","5")
		 .stream()
		 .map(x->Integer.valueOf(x))
		 .forEach(System.out::println);

??上述代码的功能是:String转Integer。结果:

1
2
3
5

2.3.7 peek

??类似于打印日志的功能在进行操作时查看当前值,示例:

		Arrays.asList("1","2","3","5")
			.stream()
			.peek(System.out::println)
			.forEach(System.out::println);

??上述代码的功能是:在遍历集合元素时,打印当前值。结果:

1
1
2
2
3
3
5
5

2.4 Stream的终止操作

??终止操作有如下几种:

1、循环 forEach
2、计算 min、max、count、 average
3、匹配 anyMatch、 allMatch、 noneMatch、findFirst、 findAny
4、汇聚 reduce
5、收集器 toArray collect

2.4.1 forEach

??循环,之前已有示例,不再赘述。

2.4.2 min

??最小值,示例:

		Integer min = Arrays.asList(1, 3, 4, 5, 2)
			.stream()
			.min((a, b) -> a - b)
			.get();
		System.out.println(min);  //1

2.4.3 max

??最大值,示例:

		Integer max = Arrays.asList(1, 3, 4, 61, 1)
			.stream()
			.max((a, b) -> a - b)
			.get();
		System.out.println(max);  //61

2.4.4 count

??统计集合中元素的数量,示例:

		long count = Arrays.asList(1, 2,3, 4, 5, 6)
			.stream()
			.count();
		System.out.print(count);  //6

2.4.5 average

??求平均值,示例:

		double avg = Arrays.asList(1, 3, 4, 61, 1)
				.stream()
				.mapToLong(x -> Long.valueOf(x + ""))
				.average()
				.getAsDouble();
		System.out.print(avg);   //14

2.4.6 findFirst

??返回第一个匹配到的元素,示例:

		Optional<Integer> first= Arrays.asList(1, 2, 3, 4, 5)
			.stream()
			.filter(x -> x % 2 == 0)
			.findFirst();
		System.out.print(first.get());  //2

2.4.7 reduce

??根据一定的规则将Stream中的元素进行计算后返回一个唯一的值,示例:

		Integer reduce = Arrays.asList(1, 2, 3, 4, 5)
			.stream()
			.reduce((a, b) -> a + b)
			.get();
		System.out.print(reduce);   //15

2.4.8 collect

??将Stream中的元素处理后,存储到固定的集合中。Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

??示例:

		List<Integer> collect = Arrays.asList(1, 2, 3, 4, 5)
			.stream()
			.filter(x -> x % 2 == 0)
			.collect(Collectors.toList());
		System.out.print(collect.toString()); //[2, 4]

??上述代码的作用是:将过滤后的元素存储到List中。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-09-01 11:47:38  更:2021-09-01 11:48:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:10:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码