文章目录
Java8新特性
Lambda表达式
- 面向对象的思想:,做一件事,找一个能解决这件事的对象,调用对象的方法完成事情
- 函数式编程思想:只要能获取到结果,谁去做的怎么做的都不重要,重视的是结果不是过程
使用Lambda表达式
package com.z.lambda.testlambda;
public class Test2 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hhh");
}
};
new Thread(runnable).start();
/*
接口内的方法没有任何参数
():看要重写的方法有没有参数
->:lambda表达式的一个标识
{}:代表了当前方法体 重写方法要做的内容
()->{System.out.println("hhh");}
*/
new Thread(()->{System.out.println("哈哈哈");}).start();
int a = 10;
int b = 20;
/* show(a, b, new Calc() {
@Override
public int add(int a, int b) {
return a+b;
}
});*/
// show(a,b,(int c,int d)->{return c+d;});//30
//可以省略形参类型: 接口中已经定义了方法的形参
// show(100,120,(c,d)->{return c+d;});//220
//当方法体只有一句代码的时候 可以省略return
show(10,120,(c,d)->c+d);//130
}
static void show(int a,int b,Calc c){
int add = c.add(a,b);
System.out.println(add);
}
}
interface Calc{
int add(int a, int b);
}
函数式接口分类
1. 自定义函数式接口
- 自定义函数式接口与已知函数接口
package com.z.lambda.func;
/*
@FunctionalInterface
检验当前接口是不是函数式接口:只能有一个抽象方法
知道的函数式接口:Runnable Comparator
*/
@FunctionalInterface//自定义函数接口
public interface Show {
int NUM = 20;
public void show();
public static void showMessage(){
System.out.println("this is showMessage()");
}
public default void c(){
System.out.println("this is c()");
}
}
2. 消费型接口
- 消费型接口的抽象方法特点:有形参,但是返回值类型是void
package com.z.lambda.consumer;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/*
消费型接口:只进不出
*/
public class Test2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李白");
list.add("杜甫");
list.add("王安石");
list.add("白居易");
/*// ↓ 四种遍历方式
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
for (String s : list) {
System.out.println(s);
}
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator<String> listIterator = list.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}*/
/*//消费型接口
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//使用lambda表达式简化
// list.forEach((l)-> {System.out.println(l);});
//当只有一个参数的时候 可以省略()
list.forEach(l-> System.out.println(l));
Map<Integer,String> map = new HashMap<>();
map.put(10,"李白");
map.put(11,"杜甫");
map.put(12,"王安石");
map.put(13,"李商隐");
/*map.forEach(new BiConsumer<Integer, String>() {
@Override
public void accept(Integer key, String value) {
System.out.println(key+"----->"+value);
}
});*/
//使用lambda表达式简化
map.forEach((k,v)->{System.out.println(k+"----->"+v);});
}
}
3. 供给型接口
- 供给型接口抽象方法特点:无参,但是有返回值
package com.z.lambda.inter;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestLambda {
public static void main(String[] args) {
Supplier<String> s = new Supplier<String>() {
@Override
public String get() {
return "你好";
}
};
System.out.println(s.get());
//当没有形参的时候,不能省略()
Supplier<String> s1 =()->"HelloWorld";
System.out.println(s1.get());
// 无限流
/*
Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
}).forEach((a)->System.out.println(a));
*/
Stream.generate(()->Math.random()).forEach((a)-> System.out.println(a));
}
}
4. 判断型接口
- 判断型接口的抽象方法特点:有参,但是返回值类型是boolean结果
package com.z.lambda.judge;
import java.util.ArrayList;
import java.util.function.Predicate;
public class Test2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李白");
list.add("杜甫");
list.add("李商隐");
list.add("白居易");
/*list.removeIf(new Predicate<String>() {
@Override
public boolean test(String s) {
if (s.startsWith("李")){
return true;
}
return false;
}
});*/
/*list.removeIf(s -> {
if (s.startsWith("李")){
return true;
}
return false;
});*/
// 三目运算符简化
list.removeIf(s -> s.startsWith("李") ? true : false);
System.out.println(list);
}
}
5. 功能型接口
- 功能型接口的抽象方法特点:既有参数又有返回值
package com.z.lambda.function;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
public class Test2 {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<>();
map.put(10,"李白");
map.put(12,"杜甫");
map.put(13,"李商隐");
map.put(14,"白居易");
/* map.replaceAll(new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String s) {
if (s.startsWith("李")){
return "hahah";
}
return null;
}
});*/
map.replaceAll((key,value)->{
if (value.startsWith("李"))
{
return "lalal";
}
return null;
});
System.out.println(map);//{10=lalal, 12=null, 13=lalal, 14=null}
}
}
方法引用与构造器引用
-
Lambda表达式是可以简化函数式接口的变星与形参赋值的语法。而方法引用和构造器引用是为了简化Iambda表达式的。当Lambda表达式满足一些特殊的情况时,还可以再简化:
- Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法来完成的
例如: System.out对象,调用println()方法来完成Lambda体
Math类,调用random()静态方法来完成Lambda体 - 并且Lambda表达式的形参正好是给该方法的实参
例如: t->System.out.printIn(t)
()-> Math.random()都是无参
- Lambda体只有一句语句,并且是通过调用一个对象的/类现有的方法来完成的
方法引用
- 方法引用的作用:简化Lambda表达式
- 方法引用的语法格式:
- 实例对象名::实例方法
- 类名::静态方法
- 类名::实例方法
- 说明:
- ::称为方法引用操作符(两个:中间不能有空格,而且必须英文状态下半角输入)
- Lambda表达式的形参列表,全部在Lambda体中使用上了,要么是作为调用方法的对象,要么是作为方法的实参。
- 在整个Lambda体中没有额外的数据。
package com.z.lambda.method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestMethod {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("李白");
list.add("杜甫");
list.add("白居易");
list.add("李商隐");
/* list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
/*list.forEach(s-> System.out.println(s));*/
list.forEach(System.out::println);
// 方法引用1
Employee e = new Employee(1, "李白", "男", 19, 9889);
/*Supplier<String> name = new Supplier<String>() {
@Override
public String get() {
return e.getName();
}
};*/
// Supplier<String> name = ()->e.getName();
//实例对象名::实例方法(实例对象名调用实例方法)
Supplier<String> name = e::getName;
System.out.println(name.get());
//方法引用2
/*Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
}).forEach(System.out::println);*/
// Stream.generate(() -> Math.random()).forEach(System.out::println);
//类名::静态方法(类名调用静态方法)
//Stream.generate(Math::random).forEach(System.out::println);
//方法引用3
String[] arr = {"c","d","a","z","e"};
/*Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});*/
// Arrays.sort(arr,((o1, o2) -> o1.compareTo(o2)));
//类名::实例方法(类调用实例方法)
Arrays.sort(arr,String::compareTo);
System.out.println(Arrays.toString(arr));
}
}
class Employee {
private int no;
private String name;
private String sex;
private int age;
private double salary;
public Employee() {
}
public Employee(int no, String name, String sex, int age, double salary) {
this.no = no;
this.name = name;
this.sex = sex;
this.age = age;
this.salary = salary;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"no=" + no +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
构造器引用
- 当Lambda表达式是创建一个对象,并且满足Lambda表达式形参,正好是给创建这个对象的构造器的实参列表。
- 当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参,正好是给创建这个数组对象的长度构造器引用的语法格式:
- 类名::new
- 数组类型名::new
package com.z.lambda.constru;
import java.util.function.Function;
import java.util.function.Supplier;
public class Test2 {
public static void main(String[] args) {
//构造器引用
/*Supplier<Employee> e = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};*/
//类名::new
Supplier<Employee> e =Employee::new;
System.out.println(e.get());
Function<Integer,int []> f = new Function<Integer, int[]>() {
@Override
public int[] apply(Integer integer) {
return new int[integer];
}
};
int[] apply = f.apply(20);
System.out.println(apply.length);
//数组类型名::new
Function<Integer,int []> f1 = int[]::new;
int[] apply1 = f1.apply(10);
System.out.println(apply1.length);
}
}
class Employee {
private int no;
private String name;
private String sex;
private int age;
private double salary;
public Employee() {
}
public Employee(int no, String name, String sex, int age, double salary) {
this.no = no;
this.name = name;
this.sex = sex;
this.age = age;
this.salary = salary;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"no=" + no +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
Stream API
- 注意:
- Stream自己不会存储元素。
- Stream不会改变源对象。每次处理都会返回一个持有结果的新Stream。
- stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
- Stream的操作三个步骤:
- 创建Stream:通过一个数据源(如:集合、数组),获取一个流
- 中间操作:中间操作是个操作链,对数据源的数据进行n次处理,但是在终结操作前,并不会真正执行。
- 终止操作:一旦执行终止操作,就执行中间操作链,最终产生结果并结束Stream,
创建Stream
- 创建Stream方式一:通过集合
Java8中的Collection接口被扩展,提供了两个获取流的方法:
- public default Stream<E> stream():返回一个顺序流
- public default Stream<E> parallelStream():返回一个并行流
package com.z.stream;
import java.util.ArrayList;
import java.util.stream.Stream;
public class CreateStream {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
/*通过集合*/
Stream<Integer> stream = list.stream();
//获取并行流
// Stream<Integer> stream = list.parallelStream();
// 方法引用
// stream.forEach(System.out::println);
stream.forEach((t)->{
System.out.println(Thread.currentThread().getName()+"===>"+t);
});
}
}
- 创建Stream方式二:通过数组
Java8中的Arrays 的静态方法 stream()可以获取数组流:
- public static <T> Stream<T> stream(T[] array):返回一个流
重载形式,能够处理对应基本类型的数组: - public static IntStream stream(int[] array):返回一个整型数据流
- public static LongStream stream(long[] array):返回一个长整型数据流
- public static DoubleStream stream(double[] array):返回一个浮点型数据流
package com.z.stream;
import java.util.Arrays;
import java.util.stream.Stream;
public class CreateStream {
public static void main(String[] args) {
int [] arr = {20 ,50,40,30,12};
Arrays.stream(arr).forEach(System.out::println);
}
}
- 创建Stream方式三:通过Stream的of()
可以调用Stream类静态方法of(),通过显示值创建一个流。它可以接收任意数量的参数。
- public static<T> Stream<T> of(T… values):返回一个顺序流
// 创建流↓ 遍历↓
Stream.of(10,20,40,30).forEach(System.out::println);
- 创建Stream方式四:创建无限流
可以使用静态方法Stream.iterate()和Stream.generate(),创建无限流。
- public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f):返回一个无限流
- public static<T> Stream<T> generate(Supplier<T> s):返回一个无限流
//无限流
/*Stream.iterate(1, new UnaryOperator<Integer>() {
@Override
public Integer apply(Integer integer) {
return 10;
}
}).forEach(System.out::println);*/
// Stream.iterate(1, (t)->t+=1).forEach(System.out::println);
Stream.generate(Math::random).forEach(System.out::println);
中间操作
package com.z.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.stream.Stream;
/*
1. 不会对原有数据造成影响
2. 中间操作的流 和 终结操作的流 必须是同一个流
*/
public class MiddleTest {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
list.add(10);
list.add(21);
list.add(30);
list.add(43);
list.add(50);
//1. 创建流
Stream<Integer> stream = list.stream();
/*stream.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return false;
}
});*/
System.out.println("========去掉偶数只保留奇数==========");
//去掉偶数只保留奇数
Stream<Integer> integerStream = stream.filter((s) -> s % 2 != 0);
integerStream.forEach(System.out::println);
System.out.println("========去掉奇数只要偶数==========");
//去掉奇数只要偶数
list.stream().filter((s) -> s % 2 == 0).forEach(System.out::println);
System.out.println("========从小到大排序==========");
//从小到大排序
list.stream().sorted().forEach(System.out::println);
System.out.println("==========从大到小排序========");
//从大到小排序
/*list.stream().sorted(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return -o1.compareTo(o2);
}
}).forEach(System.out::println);*/
list.stream().sorted((a,b)-> {return b.compareTo(a);}).forEach(System.out::println);
System.out.println("==========拿前两数========");
// limit(2):限制:取前俩个
list.stream().sorted((a,b)-> {return b.compareTo(a);}).limit(2).forEach(System.out::println);
System.out.println("==========拿第2个数,不要第一个========");
//skip(1 ):跳过一个
list.stream().sorted((a,b)-> {return b.compareTo(a);}).limit(2).skip(1 ).forEach(System.out::println);
System.out.println("=================");
String[] arr = {"hello","world","hero"};
//映射关系
Arrays.stream(arr).map((s) -> s.toUpperCase()).forEach(System.out::println);
System.out.println("=========distinct():去除重复元素========");
Stream.of(1,2,3,3,2,1,10,20).distinct().forEach(System.out::println);
}
}
终结操作
package com.z.stream;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/* 中间操作可以有多个,但是终结操作只能有一个*/
public class EndTest {
public static void main(String[] args) {
long count = Stream.of(10, 20, 30, 1, 1, 2, 3, 4, 5, 7).filter((s) -> s % 2 != 0).peek(System.out::println).count();
System.out.println("------>" + count);
/* 1
1
3
5
7
------>5
*/
System.out.println("======allMatch 判断所有元素是否都是10=======");
System.out.println("======anyMatch 任意一个元素是否是10=======");
System.out.println("======noneMatch 没有一个元素是10=======");
boolean b = Stream.of(10, 20, 30, 1, 1, 2, 3, 4, 5, 7).noneMatch((s) -> s == 10);
System.out.println(b);//false
Optional<Integer> first = Stream.of(10, 20, 30, 1, 1, 2, 3, 4, 5, 7).findFirst();
System.out.println(first.get());//10
/*collect:将满足要求的数据 进行收集*/
List<Integer> collect = Stream.of(10, 20, 30, 1, 1, 2, 3, 4, 5, 7).filter((s) -> s % 2 == 0).collect(Collectors.toList());
System.out.println(collect);//[10, 20, 30, 2, 4]
//将值反复结合,最终变为一个值
/* Optional<Integer> reduce = Stream.of(10, 20, 30).reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
});*/
Optional<Integer> reduce = Stream.of(10, 20, 30).reduce((s, s1) -> s + s1);
System.out.println(reduce.get());//60
}
}
Optional
package com.z.op;
import java.util.Optional;
public class OpTest {
public static void main(String[] args) {
String s = null;
Optional<String> s1 = Optional.ofNullable(s);
System.out.println(s1);//Optional.empty 防止空指针
System.out.println(s1.orElse("世界"));//世界
String s2 = "你好";
Optional<String> s21 = Optional.ofNullable(s2);
System.out.println(s21.orElse("世界"));//你好
Student student = new Student();
Optional<String> name = getName(student);
System.out.println(name.orElse("张三"));//orElse("张三")避免空
}
public static Optional<String> getName (Student s){
return Optional.ofNullable(s.name);//ofNullable避免空值
}
}
class Student{
String name ;
public Student() {
}
public Student(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
'}';
}
}