Optional.map - 它是如何工作的?

时间:2018-03-06 08:43:43

标签: java optional

我正在努力研究Java 8中的可选问题。我编写了一个非常简单的程序,由一个类和main()方法组成。

我希望输出数据为[aaa, DDD, ccc]。但是,我得到了[aaa, bbb, ccc]。但如果更改为s = new TestClass("DDD")到评论的那一行,我就会得到我想要的内容。

那么map()如何运作?它只能通过编辑来映射对象吗?如果我创建一个新实例并将其返回,为什么它不能正常工作?

类:

public class TestClass {
    String str;

    public TestClass(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return str;
    }
}

main()方法:

public static void main(String[] args) {
        List<TestClass> list = new ArrayList<TestClass>();
        list.add( new TestClass("aaa") );
        list.add( new TestClass("bbb") );
        list.add( new TestClass("ccc") );

        list.stream()
                .filter( s -> s.str.equals("ccc") || s.str.equals("bbb") )
                .findFirst()
                .map( s -> {
                    // s.str = "DDD";     this works just fine
                    s = new TestClass("DDD");
                    return s;
                } );

        System.out.println(list);   
    }

4 个答案:

答案 0 :(得分:2)

使用s.str = "DDD",您修改变更列表中的TestClass实例,将其str字段设置为值{{ 1}}。

使用DDD,您无法触及列表中的实例。变量s = new TestClass("DDD")是该lambda块的局部变量。为其分配新的对象引用不会更改它先前指向的对象的s字段。

通常,使用地图,您必须收集它或对结果执行某些操作。但是在这里你没有对映射结果做任何事情。

答案 1 :(得分:2)

请将您的代码更改为:

        Optional<Object> result = list.stream()
            .filter( s -> s.str.equals("ccc") || s.str.equals("bbb") )
            .findFirst()
            .map( s -> {
                // s.str = "DDD";     this works just fine
                s = new TestClass("DDD");
                return s;
            } );

    System.out.println(result); 

再次运行 - 它应该给你一些提示。

请注意,您根本不使用版本中的结果,在这种情况下修改源列表不是最佳习惯(可能存在多线程问题)

答案 2 :(得分:2)

您正在

方法中指定对象

您的新引用仅在方法范围内有效,但一旦返回,引用将指向其原始实例。

java中,这是预期的行为。

E.g:

String s = "foo";
changeString(s);
print(s); // prints "foo"

,其中

void changeString(String s) {
    s = "bar";
}

没有人禁止你更改对象属性,就像使用s.str = "DDD"一样(当然,除非你的对象是不可变的)。

在您的特定情况下,您没有对map lambda结果执行任何操作,因此您的更改将丢失。

实际上map在你的情况下是无用的,即使你只是在s.str = "DDD"内进行forEach

<强>但即可。因为你只处理一个甚至可能不存在的结果(可选),所以你应该使用

...findFirst().ifPresent(s -> s.str = "DDD" );

只有当您需要将对象转换为其他类型以进行进一步处理时,才应使用map

答案 3 :(得分:1)

'map'方法用于将每个元素映射到其对应的结果。如果要更改列表中的一个元素,则需要将结果收集到新的列表中。使用.collect()方法。

unsigned char

结果是:
aaa
DDD
CCC

整理流:

List<TestClass> list = new ArrayList<TestClass>();
    list.add( new TestClass("aaa") );
    list.add( new TestClass("bbb") );
    list.add( new TestClass("ccc") );

    List<TestClass> result = list.stream()
            .map( s -> {
                if (s.toString().equals("bbb")) {
                    s = new TestClass("DDD");
                }
                return s;
            }).collect(Collectors.toList());

    for(TestClass t : result){
        System.out.println(t);
    }