Question: I have already look at [this questions](https://stackoverflow.com/questions/36172502/replace-string-with-hashmap-value-using-java-8-stream), but my problem is a little different.

I have a "baseString", n HashMap and an output string.
I want to fill the baseString with the hashmap, to construct a json call parameters.

I have already done it with Java 7, in this way:

```
HashMap<String,Integer> element= getAllElement();

String baseElem="{\"index\":{}}\r\n" + 
        "{\"name\":\"$name$\",\"age\":$age$}";

String result=baseElem;

for (Map.Entry<String, Integer> entry : element.entrySet()) {

    result=result.replace("$name$", entry.getKey());
    result=result.replace("$age$", entry.getValue().toString());
    result=result+baseElem;
}
result= result.replace(baseElem, "");

```

Now I want to the same with Java 8,
I have tried in this way:

```
element.forEach((k,v)->{
            result=result.replaceAll("$name$", k);
            result=result.replaceAll("$age$", v.toString());
            result=result+baseElem;
        });

```

But for each result I have an error 

> 
> "Local variable result defined in an enclosing scope must be final or
>  effectively final"
> 
> 
> 

So the question is: I can do that in some kind of way with Java 8 and streams? Or there is no way, and so I can use the simple Java 7 `for`?

Answer: 
Your approach is going entirely into the wrong direction. This is not only contradicting the functional programming style, the Stream API adopts. Even the loop is horribly inefficient, performing repeated string concatenation and replace operations on the growing result string.

You did a [Shlemiel the painter’s algorithm](https://www.joelonsoftware.com/2001/12/11/back-to-basics/)

You actually only want to perform a `replace` operation on the `baseElem` template for each map entry and join all results. This can be expressed directly:

```
Map<String,Integer> element = getAllElement();

String baseElem = "{\"index\":{}}\r\n{\"name\":\"$name$\",\"age\":$age$}";

String result = element.entrySet().stream()
    .map(e -> baseElem.replace("$name$", e.getKey())
                      .replace("$age$",  e.getValue().toString()))
    .collect(Collectors.joining());

```
From the docs,

> 
> Any local variable, formal parameter, or exception parameter used but
>  not declared in a lambda expression must either be declared final or
>  be effectively final (§4.12.4), or a compile-time error occurs where
>  the use is attempted.
>  Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables **prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems**. Compared to the final restriction, it reduces the clerical burden on programmers.
> 
> 
> 

What is to be a constant here is the **reference**, but not the values.

You are getting this exception because, you are changing the reference of `result`. You are re-assigning `result` to some point to some other String inside your lambda. Thus, conflicting with the JLS, **dynamically-changing local variables**

Also, Adding to this, You can use Jackson ObjectMapper for producing JSON from Java object(s) instead of hardcoding and replacing stuff.