--- a/net/minecraft/server/players/StoredUserList.java
+++ b/net/minecraft/server/players/StoredUserList.java
@@ -15,18 +15,22 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Stream;
 import javax.annotation.Nullable;
 import net.minecraft.Util;
 import net.minecraft.util.GsonHelper;
 import org.slf4j.Logger;
 
 public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
+
     private static final Logger LOGGER = LogUtils.getLogger();
-    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
+    private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create();
     private final File file;
-    private final Map<String, V> map = Maps.newHashMap();
+    private final Map<String, V> map = Maps.newConcurrentMap(); // Paper - Use ConcurrentHashMap in JsonList
 
     public StoredUserList(File file) {
         this.file = file;
@@ -41,15 +45,19 @@
 
         try {
             this.save();
-        } catch (IOException var3) {
-            LOGGER.warn("Could not save the list after adding a user.", (Throwable)var3);
+        } catch (IOException ioexception) {
+            StoredUserList.LOGGER.warn("Could not save the list after adding a user.", ioexception);
         }
+
     }
 
     @Nullable
     public V get(K key) {
-        this.removeExpired();
-        return this.map.get(this.getKeyForUser(key));
+        // Paper start - Use ConcurrentHashMap in JsonList
+        return (V) this.map.computeIfPresent(this.getKeyForUser(key), (k, v) -> {
+            return v.hasExpired() ? null : v;
+        });
+        // Paper end - Use ConcurrentHashMap in JsonList
     }
 
     public void remove(K key) {
@@ -57,9 +65,10 @@
 
         try {
             this.save();
-        } catch (IOException var3) {
-            LOGGER.warn("Could not save the list after removing a user.", (Throwable)var3);
+        } catch (IOException ioexception) {
+            StoredUserList.LOGGER.warn("Could not save the list after removing a user.", ioexception);
         }
+
     }
 
     public void remove(StoredUserEntry<K> entry) {
@@ -67,33 +76,24 @@
     }
 
     public String[] getUserList() {
-        return this.map.keySet().toArray(new String[0]);
+        return (String[]) this.map.keySet().toArray(new String[0]);
     }
 
     public boolean isEmpty() {
-        return this.map.size() < 1;
+        return this.map.isEmpty(); // Paper - Use ConcurrentHashMap in JsonList
     }
 
     protected String getKeyForUser(K profile) {
         return profile.toString();
     }
 
-    protected boolean contains(K object) {
-        return this.map.containsKey(this.getKeyForUser(object));
+    protected boolean contains(K k0) {
+        this.removeExpired(); // CraftBukkit - SPIGOT-7589: Consistently remove expired entries to mirror .get(...)
+        return this.map.containsKey(this.getKeyForUser(k0));
     }
 
     private void removeExpired() {
-        List<K> list = Lists.newArrayList();
-
-        for (V storedUserEntry : this.map.values()) {
-            if (storedUserEntry.hasExpired()) {
-                list.add(storedUserEntry.getUser());
-            }
-        }
-
-        for (K object : list) {
-            this.map.remove(this.getKeyForUser(object));
-        }
+        this.map.values().removeIf(StoredUserEntry::hasExpired); // Paper - Use ConcurrentHashMap in JsonList
     }
 
     protected abstract StoredUserEntry<K> createEntry(JsonObject json);
@@ -103,31 +103,95 @@
     }
 
     public void save() throws IOException {
-        JsonArray jsonArray = new JsonArray();
-        this.map.values().stream().map(entry -> Util.make(new JsonObject(), entry::serialize)).forEach(jsonArray::add);
+        this.removeExpired(); // Paper - remove expired values before saving
+        JsonArray jsonarray = new JsonArray();
+        Stream<JsonObject> stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error
+            JsonObject jsonobject = new JsonObject();
 
-        try (BufferedWriter bufferedWriter = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
-            GSON.toJson(jsonArray, GSON.newJsonWriter(bufferedWriter));
+            Objects.requireNonNull(jsonlistentry);
+            return (JsonObject) Util.make(jsonobject, jsonlistentry::serialize);
+        });
+
+        Objects.requireNonNull(jsonarray);
+        stream.forEach(jsonarray::add);
+        BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
+
+        try {
+            StoredUserList.GSON.toJson(jsonarray, StoredUserList.GSON.newJsonWriter(bufferedwriter));
+        } catch (Throwable throwable) {
+            if (bufferedwriter != null) {
+                try {
+                    bufferedwriter.close();
+                } catch (Throwable throwable1) {
+                    throwable.addSuppressed(throwable1);
+                }
+            }
+
+            throw throwable;
         }
+
+        if (bufferedwriter != null) {
+            bufferedwriter.close();
+        }
+
     }
 
     public void load() throws IOException {
         if (this.file.exists()) {
-            try (BufferedReader bufferedReader = Files.newReader(this.file, StandardCharsets.UTF_8)) {
-                this.map.clear();
-                JsonArray jsonArray = GSON.fromJson(bufferedReader, JsonArray.class);
-                if (jsonArray == null) {
-                    return;
-                }
+            BufferedReader bufferedreader = Files.newReader(this.file, StandardCharsets.UTF_8);
 
-                for (JsonElement jsonElement : jsonArray) {
-                    JsonObject jsonObject = GsonHelper.convertToJsonObject(jsonElement, "entry");
-                    StoredUserEntry<K> storedUserEntry = this.createEntry(jsonObject);
-                    if (storedUserEntry.getUser() != null) {
-                        this.map.put(this.getKeyForUser(storedUserEntry.getUser()), (V)storedUserEntry);
+            label54:
+            {
+                try {
+                    this.map.clear();
+                    JsonArray jsonarray = (JsonArray) StoredUserList.GSON.fromJson(bufferedreader, JsonArray.class);
+
+                    if (jsonarray == null) {
+                        break label54;
+                    }
+
+                    Iterator iterator = jsonarray.iterator();
+
+                    while (iterator.hasNext()) {
+                        JsonElement jsonelement = (JsonElement) iterator.next();
+                        JsonObject jsonobject = GsonHelper.convertToJsonObject(jsonelement, "entry");
+                        StoredUserEntry<K> jsonlistentry = this.createEntry(jsonobject);
+
+                        if (jsonlistentry.getUser() != null) {
+                            this.map.put(this.getKeyForUser(jsonlistentry.getUser()), (V) jsonlistentry); // CraftBukkit - decompile error
+                        }
                     }
+                // Spigot Start
+                } catch ( com.google.gson.JsonParseException | NullPointerException ex )
+                {
+                    org.bukkit.Bukkit.getLogger().log( java.util.logging.Level.WARNING, "Unable to read file " + this.file + ", backing it up to {0}.backup and creating new copy.", ex );
+                    File backup = new File( this.file + ".backup" );
+                    this.file.renameTo( backup );
+                    this.file.delete();
+                // Spigot End
+                } catch (Throwable throwable) {
+                    if (bufferedreader != null) {
+                        try {
+                            bufferedreader.close();
+                        } catch (Throwable throwable1) {
+                            throwable.addSuppressed(throwable1);
+                        }
+                    }
+
+                    throw throwable;
                 }
+
+                if (bufferedreader != null) {
+                    bufferedreader.close();
+                }
+
+                return;
+            }
+
+            if (bufferedreader != null) {
+                bufferedreader.close();
             }
+
         }
     }
 }
