我最近正在阅读有关函数式编程的内容。我最常说它带来了很大的好处,但我有一些性能问题,比如渲染一个非常大的字符串时,比如连接很多字符串的 html 页面。 通常我会使用字符串生成器。但我无法在仍然遵循函数式编程范例的情况下使用它。
性能不佳代码:
如您所见
ToListItem
和 ToUl
是纯函数
class Program
{
static string ToListItem(string s)
{
return "<li>" + s + "</li>";
}
static string ToUl(string[] items)
{
return "<ul>" + String.Join("", items.Select(x => ToListItem(x))) + "</ul>";
}
static void Main(string[] args)
{
string[] items = new string[]
{
"Apple",
"Orange",
"Banana"
};
string htmlUl = ToUl(items);
Console.WriteLine(htmlUl);
}
}
更快的代码
但正如你所看到的
ToListItem
和 ToUl
不再是纯函数,我无法提供在纯函数中使用 StringBuilder
的解决方案
class Program
{
static void ToListItem(string s,StringBuilder sb)
{
sb.Append("<li>" + s + "</li>");
}
static void ToUl(string[] items, StringBuilder sb)
{
sb.Append("<ul>");
foreach (var item in items)
ToListItem(item, sb);
sb.Append("</ul>");
}
static void Main(string[] args)
{
string[] items = new string[]
{
"Apple",
"Orange",
"Banana"
};
StringBuilder sb = new StringBuilder();
ToUl(items, sb);
Console.WriteLine(sb.ToString());
}
}
所以我的问题是:
可以用函数式编程方式使用StringBuilder吗?如何?如果不是,替代的性能解决方案是什么?
更新1 我举了一些例子。这里的性能并不重要,但随着列表线性增长,性能差距将呈指数级增长。
这并不能完全解决上述情况,但它提供了一个基线,您可以在此基础上使用页眉和页脚参数为您的案例构建一些内容。
using System;
using System.Collections.Generic;
using System.Text;
public static class FunctionalStringBuilder
{
public static string BuildString<T>(this IEnumerable<T> enumerable, Func<T, string> response)
{
var builder = new StringBuilder();
foreach (var item in enumerable)
{
builder.Append(response(item));
}
return builder.ToString();
}
}
你可以这样使用它:
var list = new List<Employee>
{
AutoFaker.Generate<Employee>(),
AutoFaker.Generate<Employee>(),
AutoFaker.Generate<Employee>(),
AutoFaker.Generate<Employee>()
};
var result = list.BuildString(
e => $"Employee Id: {e.Id}, Name: {e.Name}, DateOfBirth: {e.DateOfBirth}\n");
我想你可能会回到什么是函数式编程。要实现函数式编程,您需要函数的返回值作为下一个函数继续执行等。我对您的代码有一些更改建议。
如果您看到 StringBuilder.append() 的 javaDoc,该函数将返回 StringBuilder,因此通过这些知识,您可以通过在另一个追加后调用追加来实现该方法作为函数式编程。
package org.example;
import java.util.Arrays;
import java.util.Optional;
public class StringBuilderFunctionalMain {
static StringBuilder addListItems(String[] items, StringBuilder sb) {
Arrays.stream(items)
.forEach(item -> sb.append("<li>").append(item).append("</li>"));
return sb;
}
static StringBuilder toUl(String[] items, StringBuilder sb) {
return Optional.of(sb)
.map(stringBuilder -> stringBuilder.append("<ul>"))
.map(stringBuilder -> addListItems(items, sb))
.map(stringBuilder -> stringBuilder.append("</ul>"))
.get();
}
public static void main(String[] args) {
String[] items = new String[]
{
"Apple",
"Orange",
"Banana"
};
Optional.of(new StringBuilder())
.map(sb -> toUl(items, sb))
.ifPresent(System.out::println);
}
}
这样就可以像函数式编程一样实现StringBuilder了。