java 8 部分新特性和函数式编程

1.接口可以添加非抽象的方法和静态方法,使用关键字 default 即可
代码如下:

public interface Defaulable {

    void printName();

    default void printAge(){
        System.out.println(19);
    }

     static void printSex(){
        System.out.println("女");
    }


}

实现如下:

public class DefaulableImpl implements Defaulable {
    @Override
    public void printName() {
        System.out.println("abel");
    }

    public static void main(String [] args){


        Defaulable d=new DefaulableImpl();
          d.printName();
          d.printAge();
        Defaulable.printSex();
    }
}

##Java1.8中接口和抽象类存在的不同?

当两个接口都定义两个 完全相同的 默认方法
default void printAge(){
//do Something
},
实现类同时实现这两个接口,会出现冲突。 实现类需要重新覆写该默认方法() 。

  • 抽象类允许非静态和非final的域,允许方法成为public,static和final
  • 所有的接口方法本质为public的。

JDK 8 争议性的把抽象类的优点带给接口。造成的影响是今天有大量的抽象类通过默认方法可能被替换为接口。


#2. :: 方法引用

方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

::是java 8里引入lambda后的一种用法,表示引用,

比如静态方法的引用String::valueOf;
比如构造器的引用,ArrayList::new
比如输出方法的引用 
list.forEach(System.out::println);
也可以引用类的属性。

下面,我们以定义了4个方法的Car这个类作为例子,区分Java中支持的4种不同的方法引用。

public static class Car {
    public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }              
         
    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }
         
    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }
         
    public void repair() {   
        System.out.println( "Repaired " + this.toString() );
    }
}

第一种方法引用是构造器引用,它的语法是Class::new,或者更一般的Class< T >::new。请注意构造器没有参数。

final Car car = Car.create( Car::new ); //引用 Car 的 new 构造方法
final List< Car > cars = Arrays.asList( car );

第二种方法引用是静态方法引用,它的语法是Class::static_method。请注意这个方法接受一个Car类型的参数。

cars.forEach( Car::collide );

第三种方法引用是特定类的任意对象的方法引用,它的语法是Class::method。请注意,这个方法没有参数。

cars.forEach( Car::repair );

最后,第四种方法引用是特定对象的方法引用,它的语法是instance::method。请注意,这个方法接受一个Car类型的参数

final Car police = Car.create( Car::new );
cars.forEach( police::follow );

运行上面的Java程序在控制台上会有下面的输出(Car的实例可能不一样):

Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d

#3.Clock
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。

 ZoneId zone1 = ZoneId.of("Europe/Berlin");
		
		 System.out.println(ZoneId.getAvailableZoneIds());
		 Clock clock=Clock.system(zone1);
//		 Clock clock=Clock.systemDefaultZone();//获取默认时区
		 Instant instant=clock.instant();
		 long millis = clock.millis();
		 System.out.println(millis);//可替换System.currentTimeMillis()
		 System.out.println(clock+"-----sd"+instant);

如果你需要特定时区的日期/时间,那么ZonedDateTime是你的选择。它持有ISO-8601格式具具有时区信息的日期与时间。下面是一些不同时区的例子:

 ZoneId zone1 = ZoneId.of("Europe/Berlin");
		 Clock clock=Clock.system(zone1);

		 final ZonedDateTime zonedDatetime = ZonedDateTime.now();
		 final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
		 final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
		         
		 System.out.println( zonedDatetime );
		 System.out.println( zonedDatetimeFromClock );
		 System.out.println( zonedDatetimeFromZone );

输出结果

2016-09-11T16:45:08.711+08:00[Asia/Shanghai]
2016-09-11T10:45:08.711+02:00[Europe/Berlin]
2016-09-11T01:45:08.724-07:00[America/Los_Angeles]

#4. Base64

在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。

除了这十大新特性之外,还有另外的一些新特性:

更好的类型推测机制:Java 8在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。

编译器优化:Java 8将方法的参数名加入了字节码中,这样在运行时通过反射就能获取到参数名,只需要在编译时使用-parameters参数。

并行(parallel)数组:支持对数组进行并行处理,主要是parallelSort()方法,它可以在多核机器上极大提高数组排序的速度。

并发(Concurrency):在新增Stream机制与Lambda的基础之上,加入了一些新方法来支持聚集操作。

Nashorn引擎jjs:基于Nashorn引擎的命令行工具。它接受一些JavaScript源代码为参数,并且执行这些源代码。

类依赖分析器jdeps:可以显示Java类的包级别或类级别的依赖。

JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)。


#5.Optional
Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们可以用Optional进行空值检测。

        Person person = new Person();
//        person = null;
        Boolean flag = Optional.ofNullable(person).isPresent();
        System.out.println("Full Name is set? " + flag);

如果Optional类的实例为非空值的话,isPresent()返回true,否从返回false。


#5.Lambda表达式(函数式编程)

函数式编程可以说是 声明式编程。(文章末尾有解释。)

  • 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
  • 声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。
Lambda表达式还增强了集合库。 Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及 java.util.stream 包。 流(stream)就如同迭代器(iterator),但附加了许多额外的功能。 总的来说,lambda表达式和 stream 是自Java语言添加泛型(Generics)和注解(annotation)以来最大的变化。

##Lambda 表达式简单语法:

// 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 的for 循环

	//初始化数据
	List<String> str = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			str.add(i + "");
		}
		
		//通过表达式输出,如果知道是String 型就写String 否则就写范型,java会自动识别。
		 str.forEach((String) -> System.out.println(String+";"));

 str.forEach((String) -> {
		 System.out.println(String+";");
		 System.out.println(String+"附加的操作");
		 });
		str.clear();

这样写就让代码变得简单了。
匿名类可以使用lambda表达式来代替。 同样,在实现Runnable接口时也可以这样使用:

// 1.1使用匿名内部类  
new Thread(new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("Hello world !");  
    }  
}).start();  
  
// 1.2使用 lambda expression  
new Thread(() -> System.out.println("Hello world !")).start();  
  
// 2.1使用匿名内部类  
Runnable race1 = new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("Hello world !");  
    }  
};  
  
// 2.2使用 lambda expression  
Runnable race2 = () -> System.out.println("Hello world !");  
   
// 直接调用 run 方法(没开新线程哦!)  
race1.run();  
race2.run();

##使用Lambdas排序集合

//方式一,通过首字母排序
List<String> str2 = Arrays.asList("abel", "don", "bruce", "sean");
	str2.sort((e1, e2) -> e1.compareTo(e2));
 // str2.forEach((String)->System.out.println(String+";"));
	str2.forEach((e) -> System.out.println(e));

//通过长度排序
List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
		//长度从小到大排序
		str3.sort((e1, e2) -> e1.length()-e2.length()); 
		str3.forEach((e) -> System.out.println(e));

使用这种方式也可以实现排序

List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");	
		Comparator<String> sortByName=(String e1, String e2) -> e1.length()-e2.length();
		str3.sort(sortByName); //长度从小到大排序
		str3.forEach((e) -> System.out.println(e));

#使用Lambdas和Streams
使用fileter 过滤显示

List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
		//输出长度大于3的
		str3.stream().filter((String e1) -> (e1.length() > 3)).forEach((e) -> System.out.println(e));

结果如下
abel
bruce
sean

多个过滤器组合使用,也可以这样单独的定义过滤器

List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
		//定义过滤器
		Predicate<String> lengthFilter = (String e1) -> (e1.length() > 3);
		Predicate<String> conFilter = (String e1) -> (e1.contains("a"));
		str3.stream().filter(lengthFilter).filter(conFilter).forEach((e) -> System.out.println(e));

还有limit 限定,最大最小值方法。

List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
//按首字母排序,输出前三个
	str3.stream().sorted((e1, e2) -> e1.compareTo(e2)).limit(3).forEach((e) -> System.out.println(e));
		System.out.println("------------------------------------------------------------");
		//输出长度最长的
		String max=str3.stream().max(( e1,e2) -> (e1.length() - e2.length())).get();
		//输出长度最短的
		String min=str3.stream().min(( e1,e2) -> (e1.length() - e2.length())).get();
System.out.println(max+"---"+min);	

stream 的并行计算和使用summaryStatistics方法获得stream 中元素的各种汇总数据

List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
//并行计算
		int sum=str3.stream().parallel().mapToInt(p->p.length()).sum();
		System.out.println(sum);
		//使用summaryStatistics方法获得stream 中元素的各种汇总数据
		IntSummaryStatistics sumstatis=str3.stream().mapToInt(p->p.length()).summaryStatistics();
		System.out.println("求长度平均数"+sumstatis.getAverage()+"\n长度最小的"+sumstatis.getMin()+"\n长度最大的"+sumstatis.getMax()+"\n求总和"+sumstatis.getSum());
	

除此之外 Lambdas结合 map 方法,还可以使用 collect 方法来将我们的结果集放到一个字符串,一个 Set 或一个TreeSet中这里就不做解释了

#引用类的成员变量与局部变量
Lambda可以引用类的成员变量与局部变量(如果这些变量不是final的话,它们会被隐含的转为final,这样效率更高)。例如,下面两个代码片段是等价的:

String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    ( String e ) -> System.out.print( e + separator ) );

和:

final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    ( String e ) -> System.out.print( e + separator ) );

#5. 我用Lambdas 举的一些例子

测试类。

package com.us;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Created by yangyibo on 16/12/26.
 */
public class LambdaTest {


    public static void main(String[] args) {
//        forEachT();
//        threadT();
//        sortT();
//        streamsFilterT();
//        streamsCountT();
//        personTComparator();
//        boysAndGirls();
        stringToIntT();

    }




    //Lambda 的for 循环
    private static void forEachT() {
        List<String> str = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            str.add(i + "");
        }
        str.forEach((String) -> System.out.println(String + ";"));

        str.forEach((String) -> {
            System.out.print(String + ";");
            System.out.println(String + "附加的操作");
        });
        str.clear();
    }





    //匿名类 线程操作
    private static void threadT() {

        System.out.println("current--" + Thread.currentThread().getId());

        //使用 lambda expression  开线程
        new Thread(() -> System.out.println("Hello world Thread !---" + Thread.currentThread().getId())).start();

        //使用匿名内部类   没有开线程
        Runnable race2 = () -> System.out.println("Hello world  Runnable !--" + Thread.currentThread().getId());
        race2.run();
    }





    //Comparator 排序
    private static void sortT() {
        //方式一,通过首字母排序
        List<String> str2 = Arrays.asList("abel", "don", "bruce", "sean");
        str2.sort((e1, e2) -> e1.compareTo(e2));
        str2.forEach((e) -> System.out.println(e));


        System.out.println("--------------分割线--------------------");
        //通过长度排序
        List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
        //长度从小到大排序
        str3.sort((e1, e2) -> e1.length() - e2.length());
        str3.forEach((e) -> System.out.println(e));


        System.out.println("--------------分割线--------------------");
        //通过长度排序
        List<String> str4 = Arrays.asList("abel", "don", "bruce", "sean");
        Comparator<String> sortByName = (String e1, String e2) -> e1.length() - e2.length();
        str4.sort(sortByName); //长度从小到大排序
        str4.forEach((e) -> System.out.println(e));
    }





    //过滤
    private static void streamsFilterT() {
        List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");
        //输出长度大于3的
        str3.stream().filter((String e1) -> (e1.length() > 3)).forEach((e) -> System.out.println(e));

        System.out.println("--------------分割线------------输出包涵 a 字母--------");

        //输出包涵 a 字母
        List<String> str2 = (List<String>) str3.stream().filter(x -> x.contains("a"));
        str2.forEach(e -> System.out.println(e));

        System.out.println("--------------分割线------------按首字母排序,输出前三个--------");
        //按首字母排序,输出前三个
        str3.stream().sorted((e1, e2) -> e1.compareTo(e2)).limit(3).forEach((e) -> System.out.println(e));

        System.out.println("--------------分割线--------------------");

        //输出长度最长的
        String max = str3.stream().max((e1, e2) -> (e1.length() - e2.length())).get();
        System.out.println("输出长度最长的: " + max);

        System.out.println("--------------分割线--------------------");

        //输出长度最短的
        String min = str3.stream().min((e1, e2) -> (e1.length() - e2.length())).get();
        System.out.println("输出长度最短的: " + min);
    }






    // reduce 聚合操作   使用summaryStatistics方法获得stream 中元素的各种汇总数据
    private static void streamsCountT() {
        List<String> str3 = Arrays.asList("abel", "don", "bruce", "sean");

        //并行计算
        int sum = str3.stream().parallel().mapToInt(p -> p.length()).sum();
        System.out.println(sum);

        System.out.println("--------------分割线-----------reduce---------");

        //reduce 求和
        int sum2 = str3.stream().parallel().mapToInt(p -> p.length()).reduce(0, (x, y) -> (x + y));
        System.out.println("reduce 求和" + sum2);


        System.out.println("--------------分割线--------------------");

        //使用summaryStatistics方法获得stream 中元素的各种汇总数据
        IntSummaryStatistics sumstatis = str3.stream().mapToInt(p -> p.length()).summaryStatistics();
        System.out.println("求长度平均数" + sumstatis.getAverage()
                + "\n长度最小的" + sumstatis.getMin()
                + "\n长度最大的" + sumstatis.getMax()
                + "\n求总和" + sumstatis.getSum());
    }






    //使用 Comparator 排序
    private static void personTComparator() {
        //将person 对象按照名字首字母顺序排列
        List<Person> persons = new ArrayList<>();

        for (int i = 0; i < 4; i++) {
            Person person = new Person();
            person.setName("abel-" + i);
            person.setAge(20 + i);
            persons.add(person);
        }
        Comparator<Person> byName = Comparator.comparing(Person::getName);
        persons.sort(byName);
        persons.forEach(p -> System.out.println(p.getName()));
    }







    //  使用 Collectors.groupingBy 转换为map   使用Predicate 进行过滤操作。
    public static void boysAndGirls() {
        List<Person> persons = new ArrayList<>();

        for (int i = 1; i <= 40; i++) {
            Person person = new Person();
            person.setName("abel-" + i);
            person.setSex((int) (Math.random() * 2));
            person.setAge(25 + i);
            persons.add(person);
        }
        persons.forEach(p -> System.out.println(p.toString()));

        // 统计年龄在25-65岁,且名字中包涵 "-1"或者"-2" 的男女人数、比例   0:为女性,1:为男性
        Map<Integer, Integer> result = persons.parallelStream().filter(p -> p.getAge() <= 65 && p.getAge() >= 25
                && (p.getName().contains("-1") || p.getName().contains("-2"))).
                collect(
                        //把结果收集到一个Map中,用统计到的男女自身作为键,其出现次数作为值。
                        Collectors.groupingBy(p -> p.getSex(), Collectors.summingInt(p -> 1))
                );
        System.out.println("\n" + "boysAndGirls result is " + result);


        System.out.println("--------------分割线--------------------");


        // 统计年龄在25-65岁,且名字中以"a" 开头的男女人数、比例   0:为女性,1:为男性
        Predicate<Person> startsWithA = (n) -> n.getName().startsWith("a");
        Predicate<Person> ageMax = (n) -> n.getAge() <= 65;
        Predicate<Person> ageMin = (n) -> n.getAge() >= 25;
        Map<Integer, Integer> result2 = persons.parallelStream().filter(startsWithA.and(ageMax).and(ageMin)).
                collect(
                        //把结果收集到一个Map中,用统计到的男女自身作为键,其出现次数作为值。
                        Collectors.groupingBy(p -> p.getSex(), Collectors.summingInt(p -> 1))
                );
        System.out.println("boysAndGirls Predicate  result2 is " + result2);

    }






    //使用map 转换对象。使用Collectors 返回集合 使用Comparator排序
    private static void stringToIntT() {
        //将String 集合 转换为 int 取得大于4,小于11的元素,并按从大到小排序,转换为 integer 集合。
        List<String> list = Arrays.asList("1", "3","3", "4", "5", "5", "6", "7","7", "8", "9", "10", "10", "10", "11", "12", "13", "14", "15");
        Comparator<Integer> sort = (Integer e1, Integer e2) -> e2 - e1;
        List<Integer> listInt = list.stream()
                .distinct()
                .map(x -> new Integer(x))
                .filter(x -> x > 4 && x < 11)
                .sorted(sort)
                .collect(Collectors.toList());
        listInt.forEach(e -> System.out.print(e+" , "));

    }




}

#pojo 类

public class Person {
    int age;
    String name;
    int sex;
    String group;
    List<String> friend;
    public Person() {
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public List<String> getFriend() {
        return friend;
    }

    public void setFriend(List<String> friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                ", group='" + group + '\'' +
                ", friend=" + friend +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }

    @Override
    public int hashCode() {
        int result = age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }

函数式接口 Function、Consumer、Supplier、Predicate

 /**
     * 使用场景:提前定义可能返回的一个指定类型结果,等需要调用的时候再获取结果。
     *
     * @param supplier
     * @return
     */
    public static String getSupplierValue(Supplier<String> supplier) {
        return supplier.get();
    }

    /**
     * 函数,懒加载
     */
    public static void supplierTest() {
        // 示例1
        int num1 = 100;
        int num2 = 200;
        // 提前定义好需要返回的指定类型结果,但不运行
        Supplier<Integer> supplier = () -> num1 + num2;
        //此示例中返回的结果引用的对象num1和num2其实是不能更改的,如果我们在supplier定义后,suppliser.get()调用前将num1或num更改了,则编译会报错!
        // num1 =101;
        // 调取get()方法获取一个结果
        System.out.println(supplier.get());

        // 示例2
        String str = "abcdefghijklmn";
        String s = getSupplierValue(() -> str.substring(1, 5));
        System.out.println(s);
    }


    /**
     * 函数无返回
     */
    public static void consumerTest() {
        // 传入一个加法并打印结果 30
        modify(10, x -> System.out.println(x + 20));

        // 传入一个减法并打印结果 -10
        modify(10, x -> System.out.println(x - 20));


        /**
         * 定义一个消费方法,将李四筛选出来存入 li
         */
        List<Person> li = new ArrayList<>();

        // 定义一个消费方法,li
        Consumer<Person> consumer = x -> {
            if (x.getName().equals("李四")) {
                li.add(x);
            }
        };

        List<Person> list = new ArrayList<>();
        list.add(new Person(21, "张三"));
        list.add(new Person(22, "李四"));
        list.add(new Person(23, "赵六"));
        list.add(new Person(30, "王五"));
        list.add(new Person(52, "李四"));

        // 传入一个消费方法
        list.forEach(consumer);

        // 打印消费方法处理后的li
        System.out.println(li);

    }

    /**
     * 使用场景:处理一些结果或数据,不需要返回的消费型,例如打印、发送通知等操作。
     * 定义一个方法,第二个参数为一个Consumer(对参数进行操作的函数)
     *
     * @param num
     * @param consumer
     */
    public static void modify(int num, Consumer<Integer> consumer) {
        // 执行accept()方法,方法的具体实现不关心,调用的时候才关心
        consumer.accept(num);
    }


    /**
     * 使用场景:对一个数据进行判断,并返回boolean
     * boolean test(T t) 判断指定值是否符合条件
     * Predicate<T> and(Predicate<? super T> other) 与操作
     * Predicate<T> or(Predicate<? super T> other) 或操作
     * static <T> Predicate<T> isEqual(Object targetRef) 静态方法,equals判断第一个test与第二个test方法相同
     */
    public static void predicateTest() {

        //示例1 设置断言x == 10
        Predicate<Integer> predicate = (x) -> x == 10;
        //传入x = 10
        System.out.println("x = 10 ?" + predicate.test(10));
        //断言逻辑取反
        predicate = predicate.negate();
        System.out.println("x != 10 ?" + predicate.test(10));


        //示例2 将list集合里面小于20的数据移除
        List<Integer> list = new ArrayList<>();
        list.add(9);
        list.add(12);
        list.add(21);
        list.add(60);
        // 使用lambda表达式Predicate,判断list里数是否满足条件,并删除,
        // 查看list.removeIf()方法源码,我们发现他实现的方式就是遍历集合并对每个集合元素调用Predicate.test()方法,验证结果并移除元素。
        list.removeIf(x -> x < 20);
        System.out.println(list);

        // 示例3 统计集合中相等的对象的个数
        Person p = new Person(22, "李四");
        // 使用isEqual生成一个断言
        Predicate<Person> predicate3 = Predicate.isEqual(p);
        Long count = Stream.of(
                new Person(21, "张三"),
                new Person(22, "李四"),
                new Person(23, "王五"),
                new Person(24, "王五"),
                new Person(22, "李四"),
                new Person(26, "张三")
        ).filter(predicate3).count();
        System.out.println(count);
    }


    /**
     *  函数有返回
     */
    public static void FunctionTest() {
        //示例1:定义一个 funciton ,实现将String转换为Integer
        Integer a = FunctionTest("100", x -> Integer.parseInt(x));
        // 结果:class java.lang.Integer
        System.out.println(a.getClass());

        //示例2:使用andThen() 实现一个函数 y=10x + 10; 结果30
        Function<Integer, Integer> function2 = x -> 10 * x;
        // andThen 返回首先将此函数应用于的组合函数它的输入
        function2 = function2.andThen(x -> x + 10);
        System.out.println(function2.apply(2));


        //示例3:使用compose() 实现一个函数 y=(10+x)2; 结果 26
        Function<Integer, Integer> function3 = x -> x * 2;
        // compose 将此函数应用于给定参数。
        function3 = function3.compose(x -> x + 10);
        System.out.println(function3.apply(3));


        //示例5:使用使用compose()、andThen()实现一个函数 y=(10+x)2+10; 结果 36
        Function<Integer, Integer> function4 = x -> x * 2;
        function4 = function4.compose(x -> x + 10);
        function4 = function4.andThen(x -> x + 10);
        System.out.println(function4.apply(3));

    }

    /**
     * 使用场景:根据一个数据类型得到另一个数据类型。
     * 方法:
     * <p>
     * R apply(T t); 根据一个数据类型T加工得到一个数据类型R
     * <V> Function<V, R> compose(Function<? super V, ? extends T> before) 组合函数,调用当前function之前调用
     * <V> Function<T, V> andThen(Function<? super R, ? extends V> after) 组合函数,调用当前function之后调用
     * static <T> Function<T, T> identity() 静态方法,返回与原函数参数一致的结果。x=y;
     */
    public static Integer FunctionTest(String a, Function<String, Integer> function) {
        return function.apply(a);
    }

文章最后解释一些函数式的一些特性,用于理解。

6. 函数式编程的三大特性:

##immutable data 不可变数据:
像Clojure一样,默认上变量是不可变的,如果你要改变变量,你需要把变量copy出去修改。这样一来,可以让你的程序少很多Bug。因为,程序中的状态不好维护,在并发的时候更不好维护。(你可以试想一下如果你的程序有个复杂的状态,当以后别人改你代码的时候,是很容易出bug的,在并行中这样的问题就更多了)
##first class functions:
这个技术可以让你的函数就像变量一样来使用。也就是说,你的函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数。这个有点像Javascript的Prototype
##尾递归优化:
我们知道递归的害处,那就是如果递归很深的话,stack受不了,并会导致性能大幅度下降。所以,我们使用尾递归优化技术——每次递归时都会重用stack,这样一来能够提升性能,当然,这需要语言或编译器的支持。Python就不支持。


#函数式编程的几个技术

map & reduce :

这个技术不用多说了,函数式编程最常见的技术就是对一个集合做Map和Reduce操作。这比起过程式的语言来说,在代码上要更容易阅读。(传统过程式的语言需要使用for/while循环,然后在各种变量中把数据倒过来倒过去的)这个很像C++中的STL中的foreach,find_if,count_if之流的函数的玩法。

pipeline:

这个技术的意思是,把函数实例成一个一个的action,然后,把一组action放到一个数组或是列表中,然后把数据传给这个action list,数据就像一个pipeline一样顺序地被各个函数所操作,最终得到我们想要的结果。
##recursing 递归 :
递归最大的好处就简化代码,他可以把一个复杂的问题用很简单的代码描述出来。注意:递归的精髓是描述问题,而这正是函数式编程的精髓。

currying:

把一个函数的多个参数分解成多个函数, 然后把函数多层封装起来,每层函数都返回一个函数去接收下一个参数这样,可以简化函数的多个参数。在C++中,这个很像STL中的bind_1st或是bind2nd。
##higher order function 高阶函数:
所谓高阶函数就是函数当参数,把传入的函数做一个封装,然后返回这个封装函数。现象上就是函数传进传出,就像面向对象对象满天飞一样。
#函数式的一些好处

parallelization 并行:

所谓并行的意思就是在并行环境下,各个线程之间不需要同步或互斥。

lazy evaluation 惰性求值:

这个需要编译器的支持。表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值,也就是说,语句如x:=expression; (把一个表达式的结果赋值给一个变量)明显的调用这个表达式被计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。
##determinism 确定性:
所谓确定性的意思就是像数学那样 f(x) = y ,这个函数无论在什么场景下,都会得到同样的结果,这个我们称之为函数的确定性。而不是像程序中的很多函数那样,同一个参数,却会在不同的场景下计算出不同的结果。所谓不同的场景的意思就是我们的函数会根据一些运行中的状态信息的不同而发生变化。


参考资料:http://www.importnew.com/11908.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值