Java8语法和新功能

1- 介绍

从发明JAVA语法到功能升级换代,Java已经通过一些里程碑了:
  • Java 1.0: 最开始的程序语言
  • Java 1.1, 1.2, 1.3, 1.4:  没有语法和功能很多变化
  • Java 1.5 (或Java 5):增加了一些新的概念,并有了一些大的变化。
    • 通用/泛型
    • 自动装箱/拆箱
    • 升级 foreach 功能
    • 类型安全的枚举
    • 可变参数
    • 静态导入
    • 元数据
  • Java 6,7 在语言中没有大的变化
  • Java 8: 语言一个大的变化,增加了一些新的概念和功能:
    • 默认的接口方法
    • Lambda表达式
    • 引用方法
    • 可重复的注解
    • 数据流

2- 默认方法接口

Java8让我们通过利用 default 关键字添加非抽象的方法来实现接口。这一特点也称为扩展方法。这是我们的第一个例子:
  • Formula.java
package com.yiibai.tutorial.j8.itf;

public interface Formula {

   // Declare an abstract method.
   double calculate(int a);

   // Declaring a method is not abstract.
   // Use the keyword default.
   // (return the square root of a number)
   default double sqrt(int a) {
       return Math.sqrt(a);
   }

}
FormulaImpl 类实现 Formula 接口
  • FormulaImpl.java
package com.yiibai.tutorial.j8.itf;

// Class thi hành Interface Formula
public class FormulaImpl implements Formula {

// implements abstract method
@Override
public double calculate(int a) {
    return a*a - a;
}

}
  • FormulaTest.java
package com.yiibai.tutorial.j8.itf;

public class FormulaTest {

    public static void main(String[] args) {
        Formula formula = new FormulaImpl();

        // ==> 5
        double value1 = formula.sqrt(25);
        System.out.println("Value1 = " + value1);

        // ==> 600
        double value2 = formula.calculate(25);
        System.out.println("Value2 = " + value2);

    }

}

3- 函数接口

Java8认为接口只有一个抽象方法就是函数接口。您可以使用@FunctionalInterface注释,标记你的接口为函数接口。这不是强制性的。但是,如果添加另一个抽象方法插入此注释错误地标记接口,Java编译器会通知显示有错误。
下面是使用 @FunctionalInterface 的一些实际的例子:
下面的例子是一个有效的FunctionalInterface,因为它只有一个抽象方法。
package com.yiibai.tutorial.j8.funcitf;

@FunctionalInterface
public interface Foo {

   void something();

   default void defaultMethod() {
       System.out.println("..");
   }
}
无效的例子:

有效的例子:

无效的例子:

有效的例子:

4- Lambda表达式

首先,我们来回顾Java8之前的版本是如何整理集合的。
关于在Java中比较和排序集合,可以看看下面的文章了解更多的细节:
  • SortBefore8Example.java
package com.yiibai.tutorial.j8.lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortBefore8Example {

    public static void main(String[] args) {
 
        
        // A list of the fruits.
        List<String> fruits = Arrays.asList("Grapefruit", "Apple", "Durian",
                "Cherry");
       
        // Use of Collections utility method to arrange collection.
        // Provide a Comparator.
        Collections.sort(fruits, new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }

        });

        for (String fruit : fruits) {
            System.out.println(fruit);
        }

    }
}
运行上述示例得到的结果:

Java8知道接口具有唯一的抽象方法,该方法是函数接口。因此,实现接口的时候,只需要编写一个方法来实现唯一的抽象方法。Comparator有一个唯一的抽象方法的接口,并且它是一个函数接口。可以重写上面的例子中 Java8 Lambda 的形式:
  • SortJava8Example.java
package com.yiibai.tutorial.j8.lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class SortJava8Example {

    public static void main(String[] args) {
        
        // A list of the fruits.
        List<String> fruits = Arrays.asList("Grapefruit", "Apple", "Durian",
                "Cherry");

        
        // Use of Collections utility method to rearrange the collection.
        // Provide a Comparator to the 2nd parameter of the method.
        // Comparator has only one abstract method.
        // Can write brief with Lambda expressions.
        // No need to write the name of the interface,
        // no need to write the name of the abstract method.
        Collections.sort(fruits, (String o1, String o2) -> {
            return o1.compareTo(o2);
        });

        for (String fruit : fruits) {
            System.out.println(fruit);
        }

    }
}
在语句块中,如果只有一个声明,您可以不使用{},以更简洁的方式来编写代码段。
Collections.sort(fruits, (String o1, String o2) -> o1.compareTo(o2)  );
  
Java编译程序是甚至知道如何确定什么类型来安排的元素,在这个例子中,它是字符串类型。因此比较器 (Comparator) 一定会明确比较字符串类型的数据。也可以更简明地写出。
Collections.sort(fruits, (o1, o2) -> o1.compareTo(o2));

Lambda表达式的其他例子。

  • Converter.java
package com.yiibai.tutorial.j8.lambda;

@FunctionalInterface
public interface Converter<F, T> {
    
    T convert(F from);
    
}
使用Java8之前的版本的格式转换器接口(不使用Lambda)
  • ConverterBefore8Example.java
package com.yiibai.tutorial.j8.lambda;

public class ConverterBefore8Example {

    public static void main(String[] args) {
     
        // Initialize the Converter object.
        Converter<String, Integer> converter = new Converter<String, Integer>() {

            @Override
            public Integer convert(String from) {
                return Integer.parseInt(from);
            }

        };

        // ==> 100
        Integer value = converter.convert("0100");

        System.out.println("Value = " + value);
    }
}
使用 Java8 的 Lambda 表达式:
  • ConveterJava8Example.java
package com.yiibai.tutorial.j8.lambda;

public class ConveterJava8Example {

    public static void main(String[] args) {

       
        // Converter is a FunctionalInterface
        // Using Java 8 syntax (Lambda)
        // In the case of initializing object from FunctionalInterface.
        Converter<String, Integer> converter1 = (String from) -> {
            return Integer.parseInt(from);
        };

        // ==> 100
        Integer value1 = converter1.convert("0100");

        System.out.println("Value1 = " + value1);

        // Or more simply:
        Converter<String, Integer> converter2 = (from) -> Integer
                .parseInt(from);

        // ==> 200
        Integer value2 = converter2.convert("00200");

        System.out.println("Value2 = " + value2);     

        
        // If the method has only one parameter, can ignore ().
        Converter<String, Integer> converter3 = from -> Integer
                .parseInt(from);

        // ==> 300
        Integer value3 = converter3.convert("00300");

        System.out.println("Value3 = " + value3);
        
    }

}

5- 函数接口API

Java8中有准备一个大量的函数接口,这个在 java.util.function 包提供。 在这里,我们将说明如何使用这些接口,这样就可以更容易理解Lambda表达式及其带来的方便。

5.1- java.util.function.Consumer

Consumer是Java8中可用函数接口,它有一个唯一的抽象方法接受一个输入参数,但这个方法无任务内容返回。
  • Consumer.java
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Consumer<T> {

    // Method to accept an input parameter
    // And not return anything.
   void accept(T t);

}
使用 List.forEach(Consumer) 方法:
// java.util.List extends java.util.Collection  (extends Iterable)

// Interface java.util.Iterable:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
   for (T t : this) {
       action.accept(t);
   }
}
  • ConsumerExample.java
package com.yiibai.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerExample {
    
    // Using the method List.forEach (Consumer) with Java <8.
    // Print out the elements of the list
    public static void beforeJ8() {
        List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

        list.forEach(new Consumer<String>() {

            @Override
            public void accept(String t) {
                System.out.println(t);
            }

        });
    }
    
    // Using the method List.forEach(Consumer) with Java 8 syntax.
    // (Using lambda expression).
    public static void java8Consumer() {
        List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

        list.forEach((String t) -> {
            System.out.println(t);
        });
    }
    
    // Using the method List.forEach(Consumer) with Java 8 syntax.
    // (Using lambda expression).    
    // (More simply)
    public static void java8ConsumerMoreSimple() {
        List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

        list.forEach((String t) -> System.out.println(t));
    }
    
}

5.2- java.util.function.Predicate

Java8可用的谓词函数接口,它有一个唯一的抽象方法接受一个输入参数并方法返回一个布尔值(true/false)。此方法用于计算的输入参数是否适于逻辑。
  • Predicate.java
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Predicate<T> {

   // Evaluates this predicate on the given argument.
   boolean test(T t);

}
在下面的例子中,我们将过滤整数列表,并通过使用Predicate 在 Java8和以前版本的形式来打印奇数的列表。
  • PredicateExample.java
package com.yiibai.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class PredicateExample {
    
    // Use the Stream.filter(Predicate <T>) method way Java <8.
    // Filter a list of integers and prints the odd.
    public static void beforeJ8() {
        List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);


        // Stream containing the elements of the list above.
        Stream<Integer> stream = list.stream();
 
        // A new stream contains odd
        Stream<Integer> stream2 = stream.filter(new Predicate<Integer>() {

            @Override
            public boolean test(Integer t) {
                return t % 2 == 1;
            }
        });
    }

    
    // Use the Stream.filter (Predicate <T>) method way Java>= 8.
    // Filter a list of integers and prints the odd.
    // Using Lambda expressions.
    public static void java8Predicate() {
        List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);

        // Stream containing the elements of the list above.
        Stream<Integer> stream = list.stream();

        // A new stream contains odd
        Stream<Integer> stream2 = stream.filter(t -> {
            return t % 2 == 1;
        });

        // Stream.forEach(Consumer<T>)
        stream2.forEach(t -> System.out.println(t));
    }
    
    // Use the method Stream.filter (Predicate <T>) way Java>= 8.
    // Filter a list of integers and prints the odd.
    // Using Lambda expressions.
    // Simple and more concise.
    public static void java8ConsumerMoreSimple() {
        List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);

        // Stream containing the elements of the list above.
        Stream<Integer> stream = list.stream();

        stream.filter(t -> t % 2 == 1).forEach(t -> System.out.println(t));
    }

}

5.3- java.util.function.Function

函数就是 Java8 可用函数接口。它有一个唯一的抽象方法接受输入参数,并且方法返回另一个对象。
  • Function.java
package java.util.function;

import java.util.Objects;


@FunctionalInterface
public interface Function<T, R> {

   // Applies this function to the given argument.
   // return the function result
   R apply(T t);

}
例如:给出字符串列表,以大写来打印各个元素
  • FunctionExample.java
package com.yiibai.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

public class FunctionExample {

    
    // Use Stream.map(Function) with Java syntax <8.
    // Print out the molecules in List.
    public static void beforeJ8() {
        List<String> list = Arrays.asList("a", "c", "B", "e", "g");

        // Stream containing the elements of the list.
        Stream<String> stream = list.stream();

        // Stream.map(Function):
        // <R> Stream<R> map(Function<? super T, ? extends R> mapper);
 
        // Returns a new Stream, with the elements were changed.
        Stream<String> streamUpper = stream.map(new Function<String, String>() {

            @Override
            public String apply(String t) {
                return t == null ? null : t.toUpperCase();
            }

        });

        streamUpper.forEach(t -> System.out.println(t));
    }

    public static void java8Function() {
        List<String> list = Arrays.asList("a", "c", "B", "e", "g");

        // Stream containing the elements of the list.
        Stream<String> stream = list.stream();

        stream.map(t -> t == null ? null : t.toUpperCase()).forEach(
                t -> System.out.println(t));
    }

    public static void main(String[] args) {

        beforeJ8();

        java8Function();
    }
    
}
一些相似的函数接口:
  • java.util.function.IntFunction<R>
  • java.util.function.DoubleFunction<R>
  • java.util.function.LongFunction<R>
@FunctionalInterface
public interface IntFunction<R> {
 
    R apply(int value);
}


@FunctionalInterface
public interface LongFunction<R> {
 
    R apply(long value);
}


@FunctionalInterface
public interface DoubleFunction<R> {
 
    R apply(double value);
}

5.4- java.util.function.Supplier

Supplier就是Java8的可用函数接口,具有一个唯一的的抽象方法没有参数,方法返回一个对象。
  • Supplier.java
package java.util.function;

@FunctionalInterface
public interface Supplier<T> {

    // Gets a result.
    T get();

}
  • SupplierExample.java
package com.yiibai.tutorial.j8.api;

import java.util.function.Supplier;

public class SupplierExample {
 
    // A method with parameter is Supplier<String>.
    public static void display(Supplier<String> supp) {
        System.out.println(supp.get());
    }

    // Not used Lambda.
    public static void beforeJ8() {
        display(new Supplier<String>() {

            @Override
            public String get() {
                return "Hello";
            }
        });
        display(new Supplier<String>() {

            @Override
            public String get() {
                return "World";
            }
        });
    }

    // Using Lambda expressions.
    public static void java8Supplier() {
        display(() -> {
            return "Hello";
        });

        display(() -> {
            return "World";
        });
    }
    
    // Using Lambda expressions.
    // (Write shorter).
    public static void java8SupplierShortest() {
        display(() -> "Hello");

        display(() -> "World");
    }

    public static void main(String[] args) {

    }

}

类似的函数接口:

  • java.util.function.BooleanSupplier
  • java.util.function.IntSupplier
  • java.util.function.DoubleSupplier
  • java.util.function.LongSupplier

6- 方法引用

这关系到Lambda表达式的功能。它使我们能够引用构造函数或方法而不执行它们。
方法引用和Lambda相类似的是,它们都需要由一个兼容函数接口的目标类型。
Java8中可以通过关键字::传递的方法和构造函数的引用
看细节之前,让我们来看看一个简单的例子。
myFunction是一个函数接口。它定义了一个方法有两个参数,int a 和 b,并返回整型值。
  • MyFunction.java
package com.yiibai.tutorial.j8.mref;

@FunctionalInterface
public interface MyFunction {
 
   // Define a method to do something with a and b
   // And returns int.
   public int doSomething(int a, int b);
   
}
MathUtils类有两个静态方法是用来将两个整数相加以及相减。
  • MyMathUtils.java
package com.yiibai.tutorial.j8.mref;

public class MyMathUtils {

    
    // This method has two parameters a, b and returns the int.
    // It has a structure similar to MyFunction.doSomething(int,int)
    public static int sum(int a, int b) {
        return a + b;
    }
    
    // This method has two parameters a, b and returns the int.
    // It has a structure similar to MyFunction.doSomething
    public static int minus(int a, int b) {
        return a - b;
    }

}
  • MethodReferenceExample.java
package com.yiibai.tutorial.j8.mref;

public class MethodReferenceExample {   

    // The third parameter of this method is MyFunction (A Functional Interface).
    // When using this method:
    // You can pass the reference of method, if the method is structured
    // similar to the abstract method of MyFunction.

    public static int action(int a, int b, MyFunction func) {
        return func.doSomething(a, b);
    }

    public static void main(String[] args) {
        int a = 100;
        int b = 30;

        // Pass the reference of MyMathUtils.sum method.
        // ==> 130
        int c = action(a, b, MyMathUtils::sum);

        System.out.println("c = " + c);

        // Pass the reference of MyMathUtils.minus method.
        // == 70
        int d = action(a, b, MyMathUtils::minus);

        System.out.println("d = " + d);

        // Pass the reference of Math.subtractExact method.
        // ==> 70
        int e = action(a, b, Math::subtractExact);

        System.out.println("e = " + e);
 
        // Pass the reference of Math.min method.
        // ==> 30
        int f = action(a, b, Math::min);

        System.out.println("f = " + f);
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值