JDK8中的新特性
1.lambda表达式
1.定义
Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以推导出来的就可以省略了,Lambda 表达式免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力。
2.例子
//一个线程的创建可以使用这种方法
new Thread(() -> System.out.println("多线程任务执行!")).start();
3.标准格式
标准格式3个部分:
一些参数
一个箭头
一段代码
(参数类型 参数名称) ‐> { 代码语句 } 强调的是做什么而不是怎么做
Runnable接口简化:
1. () ‐> System.out.println("多线程任务执行!")
Comparator接口简化:
2. Arrays.sort(array, (a, b) ‐> a.getAge() ‐ b.getAge());
4.前提条件
1.必须有接口,接口中有且仅有一个方法 --函数式接口一定可以的(但不限于)
2.必须有固定的格式,就是参数什么的固定的,可以推断出来
3.
2.Stream流
1.什么是stream流
Stream流不同于InputStream和OutputStream.Jdk8中的Stream流是对集合(Collerction)的增强,增强了对集合对象的聚合操作,Stram API借助于Lambda表达式,他提供了串行和并行使用fork/join并行来拆分
2.常用
1.集合获取stream流的方式
Stream<T> stream()
Stream<T> parallelStream()
2. 数组获取stream流的方式
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[]);
3. 文件获取stream流
BufferedReader bufferedReader = new BufferedReader(new FileReader("README.md"));
Stream<String> linesStream = bufferedReader.lines();
4.静态方法获取流操作
IntStream rangeStream = IntStream.range(1, 10);
rangeStream.limit(10).forEach(num -> System.out.print(num+","));
IntStream intStream = IntStream.of(1, 2, 3, 3, 4);
intStream.forEach(num -> System.out.print(num+","));
Pipelining中间操作都会返回流对象本身,这样多个操作可以串联成一个管道
forEach() --输出
map --方法用于映射每个元素到对应的结果
filter --方法用于通过设置的条件过滤出元素
limit --获取指定数量的流
public class StreamDemo1 {
public static void main(String[] args) throws FileNotFoundException {
demo1();
}
public static void getStream() throws FileNotFoundException {
List<String> nameList = Arrays.asList("Darcy", "Chris", "Linda", "Sid", "Kim", "Jack", "Poul", "Peter");
String[] nameArr = {"Darcy", "Chris", "Linda", "Sid", "Kim", "Jack", "Poul", "Peter"};
// 集合获取 Stream 流
Stream<String> nameListStream = nameList.stream();
// 集合获取并行 Stream 流
Stream<String> nameListStream2 = nameList.parallelStream();
// 数组获取 Stream 流
Stream<String> nameArrStream = Stream.of(nameArr);
// 数组获取 Stream 流
Stream<String> nameArrStream1 = Arrays.stream(nameArr);
// 文件流获取 Stream 流
BufferedReader bufferedReader = new BufferedReader(new FileReader("README.md"));
Stream<String> linesStream = bufferedReader.lines();
// 从静态方法获取流操作
IntStream rangeStream = IntStream.range(1, 10);
rangeStream.limit(10).forEach(num -> System.out.print(num+","));
IntStream intStream = IntStream.of(1, 2, 3, 3, 4);
intStream.forEach(num -> System.out.print(num+","));
}
/**
* 1. 筛选出名字长度为4的
2. 名字前面拼接 This is
3. 遍历输出
*/
public static void demo1(){
List<String> nameList = Arrays.asList("Darcy", "Chris", "Linda", "Sid", "Kim", "Jack", "Poul", "Peter");
nameList.stream()
.filter(name -> name.length() == 4)
.map(name -> "This is "+name)
.forEach(name -> System.out.println(name));
}
/**
* 转换成为大写然后收集结果,遍历输出
*/
public static void demo2(){
List<String> nameList = Arrays.asList("Darcy", "Chris", "Linda", "Sid", "Kim", "Jack", "Poul", "Peter");
List<String> collect = nameList.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
collect.forEach(name-> System.out.println(name+","));
}
/**
* 把数字值乘以2
*/
public void mapTest() {
List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// 映射成 2倍数字
List<Integer> collect = numberList.stream()
.map(number -> number * 2)
.collect(Collectors.toList());
collect.forEach(number -> System.out.print(number + ","));
System.out.println();
numberList.stream()
.map(number -> "数字 " + number + ",")
.forEach(number -> System.out.print(number));
}
/**
* flatmap把对象扁平化
*/
public void flatMapTest() {
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
List<Integer> collect = inputStream
.flatMap((childList) -> childList.stream())
.collect(Collectors.toList());
collect.forEach(number -> System.out.print(number + ","));
}
/**
* 遍历输出
*/
public void forEachTest(){
List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
numberList.stream().forEach(number -> System.out.print(number+","));
}
/**
* filter 数据筛选
* 筛选出偶数数字
*/
public void filterTest() {
List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
List<Integer> collect = numberList.stream()
.filter(number -> number % 2 == 0)
.collect(Collectors.toList());
collect.forEach(number -> System.out.print(number + ","));
}
/**
* 查找第一个数据
* 返回的是一个 Optional 对象
*/
public void findFirstTest(){
List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Optional<Integer> firstNumber = numberList.stream()
.findFirst();
System.out.println(firstNumber.orElse(-1));
}
/**
* Stream 转换为其他数据结构
*/
public void collectTest() {
List<Integer> numberList = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, 5);
// to array
Integer[] toArray = numberList.stream()
.toArray(Integer[]::new);
// to List
List<Integer> integerList = numberList.stream()
.collect(Collectors.toList());
// to set
Set<Integer> integerSet = numberList.stream()
.collect(Collectors.toSet());
System.out.println(integerSet);
// to string
String toString = numberList.stream()
.map(number -> String.valueOf(number))
.collect(Collectors.joining()).toString();
System.out.println(toString);
// to string split by ,
String toStringbJoin = numberList.stream()
.map(number -> String.valueOf(number))
.collect(Collectors.joining(",")).toString();
System.out.println(toStringbJoin);
}
/**
* 使用流操作和不使用流操作的编码风格对比
*/
public void diffTest() {
// 不使用流操作
List<String> names = Arrays.asList("Jack", "Jill", "Nate", "Kara", "Kim", "Jullie", "Paul", "Peter");
// 筛选出长度为4的名字
List<String> subList = new ArrayList<>();
for (String name : names) {
if (name.length() == 4) {
subList.add(name);
}
}
// 把值用逗号分隔
StringBuilder sbNames = new StringBuilder();
for (int i = 0; i < subList.size() - 1; i++) {
sbNames.append(subList.get(i));
sbNames.append(", ");
}
// 去掉最后一个逗号
if (subList.size() > 1) {
sbNames.append(subList.get(subList.size() - 1));
}
System.out.println(sbNames);
System.out.println("----------------");
// 使用 Stream 流操作
String nameString = names.stream()
.filter(num -> num.length() == 4)
.collect(Collectors.joining(", "));
System.out.println(nameString);
// String string = names.stream().filter(num -> num.length() == 4).map(name -> name.toUpperCase()).collect(Collectors.joining(","));
String string = names.stream()
.filter(num -> num.length() == 4)
.map(name -> name.toUpperCase())
.collect(Collectors.joining(","));
}
/**
* reduce 字符串拼接例子
*/
public void reduceTest() {
List<String> skills = Arrays.asList("java", "golang", "c++", "c", "python");
String s = skills.stream().reduce((all, skill) -> all + skill).get();
System.out.println(s);
}
/**
* 数据去重例子
*/
public void distinctTest() {
List<String> skills = Arrays.asList("java", "golang", "c++", "c", "python", "java");
List<String> collects = skills.stream().distinct().collect(Collectors.toList());
collects.forEach(skill -> System.out.println(skill));
System.out.println("---------------------------------------------");
skills = Arrays.asList("java", "golang", "c++", "c", "python", "java");
skills.stream().distinct().forEach(s -> System.out.println(s));
}
/**
* 数学计算测试
*/
public void mathTest() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
IntSummaryStatistics stats = list.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("最小值:" + stats.getMin());
System.out.println("最大值:" + stats.getMax());
System.out.println("个数:" + stats.getCount());
System.out.println("和:" + stats.getSum());
System.out.println("平均数:" + stats.getAverage());
}
/**
* 按年龄分组
*/
public void groupByTest() {
List<Integer> ageList = Arrays.asList(11, 22, 13, 14, 25, 26);
Map<String, List<Integer>> ageGrouyByMap = ageList.stream()
.collect(Collectors.groupingBy(age -> String.valueOf(age / 10)));
ageGrouyByMap.forEach((k, v) -> {
System.out.println("年龄" + k + "0多岁的有:" + v);
});
}
/**
* 按某个条件分组
* 给一组年龄,分出成年人和未成年人
*/
public void partitioningByTest() {
List<Integer> ageList = Arrays.asList(11, 22, 13, 14, 25, 26);
Map<Boolean, List<Integer>> ageMap = ageList.stream()
.collect(Collectors.partitioningBy(age -> age > 18));
System.out.println("未成年人:" + ageMap.get(false));
System.out.println("成年人:" + ageMap.get(true));
}
/**
* 生成自己的 Stream 流
*/
public void generateTest(){
// 生成自己的随机数流
Random random = new Random();
Stream<Integer> generateRandom = Stream.generate(random::nextInt);
generateRandom.limit(5).forEach(System.out::println);
// 生成自己的 UUID 流
Stream<UUID> generate = Stream.generate(UUID::randomUUID);
generate.limit(5).forEach(System.out::println);
}
/**
* 获取 / 扔掉前 n 个元素
*/
public void limitOrSkipTest() {
// 生成自己的随机数流
List<Integer> ageList = Arrays.asList(11, 22, 13, 14, 25, 26);
ageList.stream()
.limit(3)
.forEach(age -> System.out.print(age+","));
System.out.println();
ageList.stream()
.skip(3)
.forEach(age -> System.out.print(age+","));
}
/**
* 找出偶数
*/
public void lazyTest() {
// 生成自己的随机数流
List<Integer> numberLIst = Arrays.asList(1, 2, 3, 4, 5, 6);
// 找出第一个偶数
Stream<Integer> integerStream = numberLIst.stream()
.filter(number -> {
int temp = number % 2;
if (temp == 0 ){
System.out.println(number);
}
return temp == 0;
});
System.out.println("分割线");
List<Integer> collect = integerStream.collect(Collectors.toList());
}
/**
* 并行计算
*/
public void main() {
// 生成自己的随机数流,取一千万个随机数
Random random = new Random();
Stream<Integer> generateRandom = Stream.generate(random::nextInt);
List<Integer> numberList = generateRandom.limit(10000000).collect(Collectors.toList());
// 串行 - 把一千万个随机数,每个随机数 * 2 ,然后求和
long start = System.currentTimeMillis();
int sum = numberList.stream().map(number -> number * 2).mapToInt(x -> x).sum();
long end = System.currentTimeMillis();
System.out.println("串行耗时:"+(end - start)+"ms,和是:"+sum);
// 并行 - 把一千万个随机数,每个随机数 * 2 ,然后求和
start = System.currentTimeMillis();
sum = numberList.parallelStream().map(number -> number * 2).mapToInt(x -> x).sum();
end = System.currentTimeMillis();
System.out.println("并行耗时:"+(end - start)+"ms,和是:"+sum);
}
public void simpleTest(){
List<Integer> numbers = Arrays.asList(1, 2, 3);
int[] factor = new int[] { 2 };
Stream<Integer> stream = numbers.stream()
.map(e -> e * factor[0]);
factor[0] = 0;
stream.forEach(System.out::println);
}
}
3.函数式接口
1.定义
函数式接口就是有且仅有一个抽象方法的接口,java中的函数式编程就是Lambda,函数式接口可以使用于lambda表达式中,
2.格式
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
//public abstract 在抽象接口中的方法修饰上是可以省略的
}
3.例子
public interface MyFunctionalInterface {
void myMethod();
}
public class FunctionalInterface {
// 使用自定义的函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {
inter.myMethod(); // 调用自定义的函数式接口方法
}
public static void main(String[] args) {
// 调用使用函数式接口的方法
doSomething(()-> System.out.println("Lambda执行啦!"));
}
}
4.自定义
与@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface。该注解可用于一个接口的定义上
如果不使用这个注解,如果仍然满足要求,一样可以用,但是加上就必须满足,不然会报错
5.常用 java.util.function
1.Supplier接口
java.util.function.Supplier
@FunctionalInterface
public interface Supplier<T> {
T get();
}
调用这个方法就要返回一个T类型的数据,至于这个数据是如何加工出来的,可以自定义,所以是生产者
例子
public interface MyFunctionalInterface {
void myMethod();
}
public class FunctionalInterface {
// 使用自定义的函数式接口作为方法参数
private static void doSomething(MyFunctionalInterface inter) {
inter.myMethod(); // 调用自定义的函数式接口方法
}
public static void main(String[] args) {
// 调用使用函数式接口的方法
doSomething(()-> System.out.println("Lambda执行啦!"));
}
}
2.Consumer接口
java.util.function.Consumer
型参数决定。
@FunctionalInterface
public interface Consumer<T> {
//消费一个对象
void accept(T t);
//再次消费一个对象
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
例子
public class ConsumerDemo {
private static void consumeString(Consumer<String> one,Consumer<String> two) {
one.andThen(two).accept("hello");
one.accept("ddd");
}
public static void main(String[] args) {
consumeString(s-> System.out.println(s.toUpperCase()),s-> System.out.println(s.toLowerCase()));
}
}
3.Predicate接口
java.util.function.Predicate
@FunctionalInterface
public interface Predicate<T> {
//用于判断
boolean test(T t);
//既然是条件判断,就会存在与、或、非三种常见的逻辑关系。其中将两个 Predicate 条件使用“与”逻辑连接起 //来实现“并且”的效果时,可以使用default方法 and
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//它是执行了test方法之后,对结果boolean值进行“!”取反而已。一定要在调用test方法之前调用negate
default Predicate<T> negate() {
return (t) -> !test(t);
}
//or或者进行比较 在调用test之前调用or
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
public class PredicateAndTest {
public static void main(String[] args) {
//methodAnd(s-> s.contains("H"), s-> s.contains("y"),"Helloworld");
//methodOr(s-> s.contains("a"), s-> s.contains("y"),"Helloworld");
methodNegate(s-> "Helloworld".equals(s),"Helloworld");
}
private static void methodAnd(Predicate<String> one,Predicate<String> two,String str) {
boolean test = one.and(two).test(str);
System.out.println("字符串符合要求吗:" + test);
}
private static void methodOr(Predicate<String> one,Predicate<String> two,String str){
boolean test = one.or(two).test(str);
System.out.println("字符串符合要求吗or:" + test);
}
private static void methodNegate(Predicate<String> one,String str){
boolean test = one.negate().test(str);
System.out.println("字符串取反:" + test);
}
}
4.Function<T,R> 接口
简单的说就是类型转换,就是一种类型的数据转换成为另外一个类型的数据,把T类型的转换成R类型的,有进有出
@FunctionalInterface
public interface Function<T, R> {
//根据类型T的参数获取类型R的结果
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//用来进行组合操作 类似于Consumer 中的andThen
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
例子
public class FunctionDemo {
public static void main(String[] args) {
method(s -> Integer.parseInt(s),"10");
method2(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return 1;
}
});
methodAddthen(s -> Integer.parseInt(s),s->s+10,"1");
}
//String 转换成Integer类型的
private static void method(Function<String, Integer> function, String str) {
int num = function.apply(str);
System.out.println(num + 20);
}
private static void method2(Function<String, Integer> function) {
int num = function.apply("33");
System.out.println(num + 20);
}
private static void methodAddthen(Function<String, Integer> one,Function<Integer, Integer> two,String str) {
Integer apply1 = one.andThen(two).apply(str);
System.out.println(apply1 + 20);
}
}